git.delta.rocks / jrsonnet / refs/commits / 4f2e8db91a47

difftreelog

style fix clippy warnings

Yaroslav Bolyukin2024-05-17parent: #3048d02.patch.diff
in: master

8 files changed

modifiedcrates/jrsonnet-evaluator/src/arr/mod.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/arr/mod.rs
+++ b/crates/jrsonnet-evaluator/src/arr/mod.rs
@@ -1,7 +1,4 @@
-use std::{
-	any::Any,
-	num::{NonZeroU32, NonZeroUsize},
-};
+use std::{any::Any, num::NonZeroU32};
 
 use jrsonnet_gcmodule::{Cc, Trace};
 use jrsonnet_interner::IBytes;
modifiedcrates/jrsonnet-evaluator/src/evaluate/destructure.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/evaluate/destructure.rs
+++ b/crates/jrsonnet-evaluator/src/evaluate/destructure.rs
@@ -110,7 +110,11 @@
 						fn get(self: Box<Self>) -> Result<Self::Output> {
 							let full = self.full.evaluate()?;
 							let to = full.len() - self.end;
-							Ok(Val::Arr(full.slice(Some(self.start as i32), Some(to as i32), None)))
+							Ok(Val::Arr(full.slice(
+								Some(self.start as i32),
+								Some(to as i32),
+								None,
+							)))
 						}
 					}
 
modifiedcrates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth
before · crates/jrsonnet-evaluator/src/val.rs
1use std::{2	cell::RefCell,3	fmt::{self, Debug, Display},4	mem::replace,5	num::{NonZeroU32, NonZeroUsize},6	rc::Rc,7};89use jrsonnet_gcmodule::{Cc, Trace};10use jrsonnet_interner::IStr;11use jrsonnet_types::ValType;1213pub use crate::arr::{ArrValue, ArrayLike};14use crate::{15	bail,16	error::{Error, ErrorKind::*},17	function::FuncVal,18	gc::{GcHashMap, TraceBox},19	manifest::{ManifestFormat, ToStringFormat},20	tb,21	typed::BoundedUsize,22	ObjValue, Result, Unbound, WeakObjValue,23};2425pub trait ThunkValue: Trace {26	type Output;27	fn get(self: Box<Self>) -> Result<Self::Output>;28}2930#[derive(Trace)]31enum ThunkInner<T: Trace> {32	Computed(T),33	Errored(Error),34	Waiting(TraceBox<dyn ThunkValue<Output = T>>),35	Pending,36}3738/// Lazily evaluated value39#[allow(clippy::module_name_repetitions)]40#[derive(Clone, Trace)]41pub struct Thunk<T: Trace>(Cc<RefCell<ThunkInner<T>>>);4243impl<T: Trace> Thunk<T> {44	pub fn evaluated(val: T) -> Self {45		Self(Cc::new(RefCell::new(ThunkInner::Computed(val))))46	}47	pub fn new(f: impl ThunkValue<Output = T> + 'static) -> Self {48		Self(Cc::new(RefCell::new(ThunkInner::Waiting(tb!(f)))))49	}50	pub fn errored(e: Error) -> Self {51		Self(Cc::new(RefCell::new(ThunkInner::Errored(e))))52	}53	pub fn result(res: Result<T, Error>) -> Self {54		match res {55			Ok(o) => Self::evaluated(o),56			Err(e) => Self::errored(e),57		}58	}59}6061impl<T> Thunk<T>62where63	T: Clone + Trace,64{65	pub fn force(&self) -> Result<()> {66		self.evaluate()?;67		Ok(())68	}6970	/// Evaluate thunk, or return cached value71	///72	/// # Errors73	///74	/// - Lazy value evaluation returned error75	/// - This method was called during inner value evaluation76	pub fn evaluate(&self) -> Result<T> {77		match &*self.0.borrow() {78			ThunkInner::Computed(v) => return Ok(v.clone()),79			ThunkInner::Errored(e) => return Err(e.clone()),80			ThunkInner::Pending => return Err(InfiniteRecursionDetected.into()),81			ThunkInner::Waiting(..) => (),82		};83		let ThunkInner::Waiting(value) = replace(&mut *self.0.borrow_mut(), ThunkInner::Pending)84		else {85			unreachable!();86		};87		let new_value = match value.0.get() {88			Ok(v) => v,89			Err(e) => {90				*self.0.borrow_mut() = ThunkInner::Errored(e.clone());91				return Err(e);92			}93		};94		*self.0.borrow_mut() = ThunkInner::Computed(new_value.clone());95		Ok(new_value)96	}97}9899pub trait ThunkMapper<Input>: Trace {100	type Output;101	fn map(self, from: Input) -> Result<Self::Output>;102}103impl<Input> Thunk<Input>104where105	Input: Trace + Clone,106{107	pub fn map<M>(self, mapper: M) -> Thunk<M::Output>108	where109		M: ThunkMapper<Input>,110		M::Output: Trace,111	{112		#[derive(Trace)]113		struct Mapped<Input: Trace, Mapper: Trace> {114			inner: Thunk<Input>,115			mapper: Mapper,116		}117		impl<Input, Mapper> ThunkValue for Mapped<Input, Mapper>118		where119			Input: Trace + Clone,120			Mapper: ThunkMapper<Input>,121		{122			type Output = Mapper::Output;123124			fn get(self: Box<Self>) -> Result<Self::Output> {125				let value = self.inner.evaluate()?;126				let mapped = self.mapper.map(value)?;127				Ok(mapped)128			}129		}130131		Thunk::new(Mapped::<Input, M> {132			inner: self,133			mapper,134		})135	}136}137138impl<T: Trace> From<Result<T>> for Thunk<T> {139	fn from(value: Result<T>) -> Self {140		match value {141			Ok(o) => Self::evaluated(o),142			Err(e) => Self::errored(e),143		}144	}145}146impl<T, V: Trace> From<T> for Thunk<V>147where148	T: ThunkValue<Output = V>,149{150	fn from(value: T) -> Self {151		Self::new(value)152	}153}154155impl<T: Trace + Default> Default for Thunk<T> {156	fn default() -> Self {157		Self::evaluated(T::default())158	}159}160161type CacheKey = (Option<WeakObjValue>, Option<WeakObjValue>);162163#[derive(Trace, Clone)]164pub struct CachedUnbound<I, T>165where166	I: Unbound<Bound = T>,167	T: Trace,168{169	cache: Cc<RefCell<GcHashMap<CacheKey, T>>>,170	value: I,171}172impl<I: Unbound<Bound = T>, T: Trace> CachedUnbound<I, T> {173	pub fn new(value: I) -> Self {174		Self {175			cache: Cc::new(RefCell::new(GcHashMap::new())),176			value,177		}178	}179}180impl<I: Unbound<Bound = T>, T: Clone + Trace> Unbound for CachedUnbound<I, T> {181	type Bound = T;182	fn bind(&self, sup: Option<ObjValue>, this: Option<ObjValue>) -> Result<T> {183		let cache_key = (184			sup.as_ref().map(|s| s.clone().downgrade()),185			this.as_ref().map(|t| t.clone().downgrade()),186		);187		{188			if let Some(t) = self.cache.borrow().get(&cache_key) {189				return Ok(t.clone());190			}191		}192		let bound = self.value.bind(sup, this)?;193194		{195			let mut cache = self.cache.borrow_mut();196			cache.insert(cache_key, bound.clone());197		}198199		Ok(bound)200	}201}202203impl<T: Debug + Trace> Debug for Thunk<T> {204	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {205		write!(f, "Lazy")206	}207}208impl<T: Trace> PartialEq for Thunk<T> {209	fn eq(&self, other: &Self) -> bool {210		Cc::ptr_eq(&self.0, &other.0)211	}212}213214/// Represents a Jsonnet value, which can be sliced or indexed (string or array).215#[allow(clippy::module_name_repetitions)]216pub enum IndexableVal {217	/// String.218	Str(IStr),219	/// Array.220	Arr(ArrValue),221}222impl IndexableVal {223	pub fn to_array(self) -> ArrValue {224		match self {225			Self::Str(s) => ArrValue::chars(s.chars()),226			Self::Arr(arr) => arr,227		}228	}229	/// Slice the value.230	///231	/// # Implementation232	///233	/// For strings, will create a copy of specified interval.234	///235	/// For arrays, nothing will be copied on this call, instead [`ArrValue::Slice`] view will be returned.236	pub fn slice(237		self,238		index: Option<i32>,239		end: Option<i32>,240		step: Option<BoundedUsize<1, { i32::MAX as usize }>>,241	) -> Result<Self> {242		match &self {243			Self::Str(s) => {244				let mut computed_len = None;245				let mut get_len = || {246					computed_len.map_or_else(247						|| {248							let len = s.chars().count();249							let _ = computed_len.insert(len);250							len251						},252						|len| len,253					)254				};255				let mut get_idx = |pos: Option<i32>, default| {256					match pos {257						Some(v) if v < 0 => get_len().saturating_sub((-v) as usize),258						// No need to clamp, as iterator interface is used259						Some(v) => v as usize,260						None => default,261					}262				};263264				let index = get_idx(index, 0);265				let end = get_idx(end, usize::MAX);266				let step = step.as_deref().copied().unwrap_or(1);267268				if index >= end {269					return Ok(Self::Str("".into()));270				}271272				Ok(Self::Str(273					(s.chars()274						.skip(index)275						.take(end - index)276						.step_by(step)277						.collect::<String>())278					.into(),279				))280			}281			Self::Arr(arr) => Ok(Self::Arr(arr.clone().slice(282				index,283				end,284				step.map(|v| NonZeroU32::new(v.value() as u32).expect("bounded != 0")),285			))),286		}287	}288}289290#[derive(Debug, Clone, Trace)]291pub enum StrValue {292	Flat(IStr),293	Tree(Rc<(StrValue, StrValue, usize)>),294}295impl StrValue {296	pub fn concat(a: Self, b: Self) -> Self {297		// TODO: benchmark for an optimal value, currently just a arbitrary choice298		const STRING_EXTEND_THRESHOLD: usize = 100;299300		if a.is_empty() {301			b302		} else if b.is_empty() {303			a304		} else if a.len() + b.len() < STRING_EXTEND_THRESHOLD {305			Self::Flat(format!("{a}{b}").into())306		} else {307			let len = a.len() + b.len();308			Self::Tree(Rc::new((a, b, len)))309		}310	}311	pub fn into_flat(self) -> IStr {312		#[cold]313		fn write_buf(s: &StrValue, out: &mut String) {314			match s {315				StrValue::Flat(f) => out.push_str(f),316				StrValue::Tree(t) => {317					write_buf(&t.0, out);318					write_buf(&t.1, out);319				}320			}321		}322		match self {323			Self::Flat(f) => f,324			Self::Tree(_) => {325				let mut buf = String::with_capacity(self.len());326				write_buf(&self, &mut buf);327				buf.into()328			}329		}330	}331	pub fn len(&self) -> usize {332		match self {333			Self::Flat(v) => v.len(),334			Self::Tree(t) => t.2,335		}336	}337	pub fn is_empty(&self) -> bool {338		match self {339			Self::Flat(v) => v.is_empty(),340			// Can't create non-flat empty string341			Self::Tree(_) => false,342		}343	}344}345impl<T> From<T> for StrValue346where347	IStr: From<T>,348{349	fn from(value: T) -> Self {350		Self::Flat(IStr::from(value))351	}352}353impl Display for StrValue {354	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {355		match self {356			Self::Flat(v) => write!(f, "{v}"),357			Self::Tree(t) => {358				write!(f, "{}", t.0)?;359				write!(f, "{}", t.1)360			}361		}362	}363}364impl PartialEq for StrValue {365	// False positive, into_flat returns not StrValue, but IStr, thus no infinite recursion here.366	#[allow(clippy::unconditional_recursion)]367	fn eq(&self, other: &Self) -> bool {368		let a = self.clone().into_flat();369		let b = other.clone().into_flat();370		a == b371	}372}373impl Eq for StrValue {}374impl PartialOrd for StrValue {375	fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {376		Some(self.cmp(other))377	}378}379impl Ord for StrValue {380	fn cmp(&self, other: &Self) -> std::cmp::Ordering {381		let a = self.clone().into_flat();382		let b = other.clone().into_flat();383		a.cmp(&b)384	}385}386387/// Represents any valid Jsonnet value.388#[derive(Debug, Clone, Trace, Default)]389pub enum Val {390	/// Represents a Jsonnet boolean.391	Bool(bool),392	/// Represents a Jsonnet null value.393	#[default]394	Null,395	/// Represents a Jsonnet string.396	Str(StrValue),397	/// Represents a Jsonnet number.398	/// Should be finite, and not NaN399	/// This restriction isn't enforced by enum, as enum field can't be marked as private400	Num(f64),401	/// Experimental bigint402	#[cfg(feature = "exp-bigint")]403	BigInt(#[trace(skip)] Box<num_bigint::BigInt>),404	/// Represents a Jsonnet array.405	Arr(ArrValue),406	/// Represents a Jsonnet object.407	Obj(ObjValue),408	/// Represents a Jsonnet function.409	Func(FuncVal),410}411412#[cfg(target_pointer_width = "64")]413static_assertions::assert_eq_size!(Val, [u8; 24]);414415impl From<IndexableVal> for Val {416	fn from(v: IndexableVal) -> Self {417		match v {418			IndexableVal::Str(s) => Self::string(s),419			IndexableVal::Arr(a) => Self::Arr(a),420		}421	}422}423424impl Val {425	pub const fn as_bool(&self) -> Option<bool> {426		match self {427			Self::Bool(v) => Some(*v),428			_ => None,429		}430	}431	pub const fn as_null(&self) -> Option<()> {432		match self {433			Self::Null => Some(()),434			_ => None,435		}436	}437	pub fn as_str(&self) -> Option<IStr> {438		match self {439			Self::Str(s) => Some(s.clone().into_flat()),440			_ => None,441		}442	}443	pub const fn as_num(&self) -> Option<f64> {444		match self {445			Self::Num(n) => Some(*n),446			_ => None,447		}448	}449	pub fn as_arr(&self) -> Option<ArrValue> {450		match self {451			Self::Arr(a) => Some(a.clone()),452			_ => None,453		}454	}455	pub fn as_obj(&self) -> Option<ObjValue> {456		match self {457			Self::Obj(o) => Some(o.clone()),458			_ => None,459		}460	}461	pub fn as_func(&self) -> Option<FuncVal> {462		match self {463			Self::Func(f) => Some(f.clone()),464			_ => None,465		}466	}467468	/// Creates `Val::Num` after checking for numeric overflow.469	/// As numbers are `f64`, we can just check for their finity.470	pub fn new_checked_num(num: f64) -> Result<Self> {471		if num.is_finite() {472			Ok(Self::Num(num))473		} else {474			bail!("overflow")475		}476	}477478	pub const fn value_type(&self) -> ValType {479		match self {480			Self::Str(..) => ValType::Str,481			Self::Num(..) => ValType::Num,482			#[cfg(feature = "exp-bigint")]483			Self::BigInt(..) => ValType::BigInt,484			Self::Arr(..) => ValType::Arr,485			Self::Obj(..) => ValType::Obj,486			Self::Bool(_) => ValType::Bool,487			Self::Null => ValType::Null,488			Self::Func(..) => ValType::Func,489		}490	}491492	pub fn manifest(&self, format: impl ManifestFormat) -> Result<String> {493		fn manifest_dyn(val: &Val, manifest: &dyn ManifestFormat) -> Result<String> {494			manifest.manifest(val.clone())495		}496		manifest_dyn(self, &format)497	}498499	pub fn to_string(&self) -> Result<IStr> {500		Ok(match self {501			Self::Bool(true) => "true".into(),502			Self::Bool(false) => "false".into(),503			Self::Null => "null".into(),504			Self::Str(s) => s.clone().into_flat(),505			_ => self.manifest(ToStringFormat).map(IStr::from)?,506		})507	}508509	pub fn into_indexable(self) -> Result<IndexableVal> {510		Ok(match self {511			Self::Str(s) => IndexableVal::Str(s.into_flat()),512			Self::Arr(arr) => IndexableVal::Arr(arr),513			_ => bail!(ValueIsNotIndexable(self.value_type())),514		})515	}516517	pub fn function(function: impl Into<FuncVal>) -> Self {518		Self::Func(function.into())519	}520	pub fn string(string: impl Into<StrValue>) -> Self {521		Self::Str(string.into())522	}523}524525impl From<IStr> for Val {526	fn from(value: IStr) -> Self {527		Self::string(value)528	}529}530impl From<String> for Val {531	fn from(value: String) -> Self {532		Self::string(value)533	}534}535impl From<&str> for Val {536	fn from(value: &str) -> Self {537		Self::string(value)538	}539}540impl From<ObjValue> for Val {541	fn from(value: ObjValue) -> Self {542		Self::Obj(value)543	}544}545546const fn is_function_like(val: &Val) -> bool {547	matches!(val, Val::Func(_))548}549550/// Native implementation of `std.primitiveEquals`551pub fn primitive_equals(val_a: &Val, val_b: &Val) -> Result<bool> {552	Ok(match (val_a, val_b) {553		(Val::Bool(a), Val::Bool(b)) => a == b,554		(Val::Null, Val::Null) => true,555		(Val::Str(a), Val::Str(b)) => a == b,556		(Val::Num(a), Val::Num(b)) => (a - b).abs() <= f64::EPSILON,557		#[cfg(feature = "exp-bigint")]558		(Val::BigInt(a), Val::BigInt(b)) => a == b,559		(Val::Arr(_), Val::Arr(_)) => {560			bail!("primitiveEquals operates on primitive types, got array")561		}562		(Val::Obj(_), Val::Obj(_)) => {563			bail!("primitiveEquals operates on primitive types, got object")564		}565		(a, b) if is_function_like(a) && is_function_like(b) => {566			bail!("cannot test equality of functions")567		}568		(_, _) => false,569	})570}571572/// Native implementation of `std.equals`573pub fn equals(val_a: &Val, val_b: &Val) -> Result<bool> {574	if val_a.value_type() != val_b.value_type() {575		return Ok(false);576	}577	match (val_a, val_b) {578		(Val::Arr(a), Val::Arr(b)) => {579			if ArrValue::ptr_eq(a, b) {580				return Ok(true);581			}582			if a.len() != b.len() {583				return Ok(false);584			}585			for (a, b) in a.iter().zip(b.iter()) {586				if !equals(&a?, &b?)? {587					return Ok(false);588				}589			}590			Ok(true)591		}592		(Val::Obj(a), Val::Obj(b)) => {593			if ObjValue::ptr_eq(a, b) {594				return Ok(true);595			}596			let fields = a.fields(597				#[cfg(feature = "exp-preserve-order")]598				false,599			);600			if fields601				!= b.fields(602					#[cfg(feature = "exp-preserve-order")]603					false,604				) {605				return Ok(false);606			}607			for field in fields {608				if !equals(609					&a.get(field.clone())?.expect("field exists"),610					&b.get(field)?.expect("field exists"),611				)? {612					return Ok(false);613				}614			}615			Ok(true)616		}617		(a, b) => Ok(primitive_equals(a, b)?),618	}619}
modifiedcrates/jrsonnet-macros/src/lib.rsdiffbeforeafterboth
--- a/crates/jrsonnet-macros/src/lib.rs
+++ b/crates/jrsonnet-macros/src/lib.rs
@@ -218,8 +218,7 @@
 	item: proc_macro::TokenStream,
 ) -> proc_macro::TokenStream {
 	let attr = parse_macro_input!(attr as BuiltinAttrs);
-	let item_fn = item.clone();
-	let item_fn: ItemFn = parse_macro_input!(item_fn);
+	let item_fn = parse_macro_input!(item as ItemFn);
 
 	match builtin_inner(attr, item_fn) {
 		Ok(v) => v.into(),
modifiedcrates/jrsonnet-stdlib/src/manifest/toml.rsdiffbeforeafterboth
--- a/crates/jrsonnet-stdlib/src/manifest/toml.rs
+++ b/crates/jrsonnet-stdlib/src/manifest/toml.rs
@@ -4,7 +4,7 @@
 	bail,
 	manifest::{escape_string_json_buf, ManifestFormat},
 	val::ArrValue,
-	IStr, ObjValue, Result, ResultExt, Val, State,
+	IStr, ObjValue, Result, ResultExt, State, Val,
 };
 
 pub struct TomlFormat<'s> {
modifiedcrates/jrsonnet-stdlib/src/manifest/xml.rsdiffbeforeafterboth
--- a/crates/jrsonnet-stdlib/src/manifest/xml.rs
+++ b/crates/jrsonnet-stdlib/src/manifest/xml.rs
@@ -1,9 +1,9 @@
 use jrsonnet_evaluator::{
 	bail,
 	manifest::{ManifestFormat, ToStringFormat},
-	typed::{ComplexValType, Either2, Either4, Typed, ValType},
-	val::{ArrValue, IndexableVal},
-	Either, ObjValue, Result, ResultExt, Val, State,
+	typed::{ComplexValType, Either2, Typed, ValType},
+	val::ArrValue,
+	Either, ObjValue, Result, ResultExt, State, Val,
 };
 
 pub struct XmlJsonmlFormat {
@@ -39,20 +39,20 @@
 
 	fn from_untyped(untyped: Val) -> Result<Self> {
 		let val = <Either![ArrValue, String]>::from_untyped(untyped)
-			.with_description(|| format!("parsing JSONML value (an array or string)"))?;
+			.description("parsing JSONML value (an array or string)")?;
 		let arr = match val {
 			Either2::A(a) => a,
 			Either2::B(s) => return Ok(Self::String(s)),
 		};
-		if arr.len() < 1 {
+		if arr.is_empty() {
 			bail!("JSONML value should have tag (array length should be >=1)");
 		};
 		let tag = String::from_untyped(
 			arr.get(0)
-				.with_description(|| "getting JSONML tag")?
+				.description("getting JSONML tag")?
 				.expect("length checked"),
 		)
-		.with_description(|| format!("parsing JSONML tag"))?;
+		.description("parsing JSONML tag")?;
 
 		let (has_attrs, attrs) = if arr.len() >= 2 {
 			let maybe_attrs = arr
@@ -71,7 +71,7 @@
 			tag,
 			attrs,
 			children: State::push_description(
-				|| format!("parsing children"),
+				|| "parsing children".to_owned(),
 				|| {
 					Typed::from_untyped(Val::Arr(arr.slice(
 						Some(if has_attrs { 2 } else { 1 }),
@@ -100,7 +100,7 @@
 		} => {
 			let has_children = !children.is_empty();
 			buf.push('<');
-			buf.push_str(&tag);
+			buf.push_str(tag);
 			attrs.run_assertions()?;
 			for (key, value) in attrs.iter(
 				// Not much sense to preserve order here
@@ -125,12 +125,12 @@
 			}
 			buf.push('>');
 			for child in children {
-				manifest_jsonml(&child, buf, opts)?;
+				manifest_jsonml(child, buf, opts)?;
 			}
 			if has_children || opts.force_closing {
 				buf.push('<');
 				buf.push('/');
-				buf.push_str(&tag);
+				buf.push_str(tag);
 				buf.push('>');
 			}
 			Ok(())
@@ -177,8 +177,8 @@
 	}
 	if !found {
 		// No match - no escapes required
-		out.push_str(&str);
+		out.push_str(str);
 		return;
 	}
-	out.push_str(&remaining);
+	out.push_str(remaining);
 }
modifiedcrates/jrsonnet-stdlib/src/misc.rsdiffbeforeafterboth
--- a/crates/jrsonnet-stdlib/src/misc.rs
+++ b/crates/jrsonnet-stdlib/src/misc.rs
@@ -28,8 +28,7 @@
 	o: ObjValue,
 	f: IStr,
 	default: Option<Thunk<Val>>,
-	#[default(true)]
-	inc_hidden: bool,
+	#[default(true)] inc_hidden: bool,
 ) -> Result<Val> {
 	let do_default = move || {
 		let Some(default) = default else {
modifiedcrates/jrsonnet-stdlib/src/objects.rsdiffbeforeafterboth
--- a/crates/jrsonnet-stdlib/src/objects.rs
+++ b/crates/jrsonnet-stdlib/src/objects.rs
@@ -57,8 +57,7 @@
 	o: ObjValue,
 	include_hidden: bool,
 
-	#[cfg(feature = "exp-preserve-order")]
-	preserve_order: bool,
+	#[cfg(feature = "exp-preserve-order")] preserve_order: bool,
 ) -> ArrValue {
 	o.values_ex(
 		include_hidden,
@@ -101,8 +100,7 @@
 	o: ObjValue,
 	include_hidden: bool,
 
-	#[cfg(feature = "exp-preserve-order")]
-	preserve_order: bool,
+	#[cfg(feature = "exp-preserve-order")] preserve_order: bool,
 ) -> ArrValue {
 	o.key_values_ex(
 		include_hidden,