git.delta.rocks / jrsonnet / refs/commits / 94fa86f59bc6

difftreelog

source

crates/jrsonnet-evaluator/src/val.rs19.4 KiBsourcehistory
1use std::{cell::RefCell, fmt::Debug, rc::Rc};23use gcmodule::{Cc, Trace};4use jrsonnet_interner::IStr;5use jrsonnet_parser::{LocExpr, ParamsDesc};6use jrsonnet_types::ValType;78use crate::{9	builtin::manifest::{10		manifest_json_ex, manifest_yaml_ex, ManifestJsonOptions, ManifestType, ManifestYamlOptions,11	},12	cc_ptr_eq,13	error::{Error::*, LocError},14	evaluate,15	function::{16		parse_default_function_call, parse_function_call, ArgsLike, Builtin, CallLocation,17		StaticBuiltin,18	},19	gc::TraceBox,20	throw, Context, ObjValue, Result, State,21};2223pub trait LazyValValue: Trace {24	fn get(self: Box<Self>, s: State) -> Result<Val>;25}2627#[derive(Trace)]28enum LazyValInternals {29	Computed(Val),30	Errored(LocError),31	Waiting(TraceBox<dyn LazyValValue>),32	Pending,33}3435#[allow(clippy::module_name_repetitions)]36#[derive(Clone, Trace)]37pub struct LazyVal(Cc<RefCell<LazyValInternals>>);38impl LazyVal {39	pub fn new(f: TraceBox<dyn LazyValValue>) -> Self {40		Self(Cc::new(RefCell::new(LazyValInternals::Waiting(f))))41	}42	pub fn new_resolved(val: Val) -> Self {43		Self(Cc::new(RefCell::new(LazyValInternals::Computed(val))))44	}45	pub fn force(&self, s: State) -> Result<()> {46		self.evaluate(s)?;47		Ok(())48	}49	pub fn evaluate(&self, s: State) -> Result<Val> {50		match &*self.0.borrow() {51			LazyValInternals::Computed(v) => return Ok(v.clone()),52			LazyValInternals::Errored(e) => return Err(e.clone()),53			LazyValInternals::Pending => return Err(InfiniteRecursionDetected.into()),54			LazyValInternals::Waiting(..) => (),55		};56		let value = if let LazyValInternals::Waiting(value) =57			std::mem::replace(&mut *self.0.borrow_mut(), LazyValInternals::Pending)58		{59			value60		} else {61			unreachable!()62		};63		let new_value = match value.0.get(s) {64			Ok(v) => v,65			Err(e) => {66				*self.0.borrow_mut() = LazyValInternals::Errored(e.clone());67				return Err(e);68			}69		};70		*self.0.borrow_mut() = LazyValInternals::Computed(new_value.clone());71		Ok(new_value)72	}73}7475impl Debug for LazyVal {76	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {77		write!(f, "Lazy")78	}79}80impl PartialEq for LazyVal {81	fn eq(&self, other: &Self) -> bool {82		cc_ptr_eq(&self.0, &other.0)83	}84}8586#[derive(Debug, PartialEq, Trace)]87pub struct FuncDesc {88	pub name: IStr,89	pub ctx: Context,90	pub params: ParamsDesc,91	pub body: LocExpr,92}93impl FuncDesc {94	/// Create body context, but fill arguments without defaults with lazy error95	pub fn default_body_context(&self) -> Context {96		parse_default_function_call(self.ctx.clone(), &self.params)97	}9899	/// Create context, with which body code will run100	pub fn call_body_context(101		&self,102		s: State,103		call_ctx: Context,104		args: &dyn ArgsLike,105		tailstrict: bool,106	) -> Result<Context> {107		parse_function_call(108			s,109			call_ctx,110			self.ctx.clone(),111			&self.params,112			args,113			tailstrict,114		)115	}116}117118#[allow(clippy::module_name_repetitions)]119#[derive(Trace, Clone)]120pub enum FuncVal {121	/// Plain function implemented in jsonnet122	Normal(Cc<FuncDesc>),123	/// Standard library function124	StaticBuiltin(#[skip_trace] &'static dyn StaticBuiltin),125	/// User-provided function126	Builtin(Cc<TraceBox<dyn Builtin>>),127}128129impl Debug for FuncVal {130	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {131		match self {132			Self::Normal(arg0) => f.debug_tuple("Normal").field(arg0).finish(),133			Self::StaticBuiltin(arg0) => {134				f.debug_tuple("StaticBuiltin").field(&arg0.name()).finish()135			}136			Self::Builtin(arg0) => f.debug_tuple("Builtin").field(&arg0.name()).finish(),137		}138	}139}140141impl FuncVal {142	pub fn args_len(&self) -> usize {143		match self {144			Self::Normal(n) => n.params.iter().filter(|p| p.1.is_none()).count(),145			Self::StaticBuiltin(i) => i.params().iter().filter(|p| !p.has_default).count(),146			Self::Builtin(i) => i.params().iter().filter(|p| !p.has_default).count(),147		}148	}149	pub fn name(&self) -> IStr {150		match self {151			Self::Normal(normal) => normal.name.clone(),152			Self::StaticBuiltin(builtin) => builtin.name().into(),153			Self::Builtin(builtin) => builtin.name().into(),154		}155	}156	pub fn evaluate(157		&self,158		s: State,159		call_ctx: Context,160		loc: CallLocation,161		args: &dyn ArgsLike,162		tailstrict: bool,163	) -> Result<Val> {164		match self {165			Self::Normal(func) => {166				let body_ctx = func.call_body_context(s.clone(), call_ctx, args, tailstrict)?;167				evaluate(s, body_ctx, &func.body)168			}169			Self::StaticBuiltin(b) => b.call(s, call_ctx, loc, args),170			Self::Builtin(b) => b.call(s, call_ctx, loc, args),171		}172	}173	pub fn evaluate_simple(&self, s: State, args: &dyn ArgsLike) -> Result<Val> {174		self.evaluate(s, Context::default(), CallLocation::native(), args, true)175	}176}177178#[derive(Clone)]179pub enum ManifestFormat {180	YamlStream(Box<ManifestFormat>),181	Yaml {182		padding: usize,183		#[cfg(feature = "exp-preserve-order")]184		preserve_order: bool,185	},186	Json {187		padding: usize,188		#[cfg(feature = "exp-preserve-order")]189		preserve_order: bool,190	},191	ToString,192	String,193}194impl ManifestFormat {195	#[cfg(feature = "exp-preserve-order")]196	fn preserve_order(&self) -> bool {197		match self {198			ManifestFormat::YamlStream(s) => s.preserve_order(),199			ManifestFormat::Yaml { preserve_order, .. } => *preserve_order,200			ManifestFormat::Json { preserve_order, .. } => *preserve_order,201			ManifestFormat::ToString => false,202			ManifestFormat::String => false,203		}204	}205}206207#[derive(Debug, Clone, Trace)]208pub struct Slice {209	pub(crate) inner: ArrValue,210	pub(crate) from: u32,211	pub(crate) to: u32,212	pub(crate) step: u32,213}214impl Slice {215	const fn from(&self) -> usize {216		self.from as usize217	}218	const fn to(&self) -> usize {219		self.to as usize220	}221	const fn step(&self) -> usize {222		self.step as usize223	}224	const fn len(&self) -> usize {225		// TODO: use div_ceil226		let diff = self.to() - self.from();227		let rem = diff % self.step();228		let div = diff / self.step();229230		if rem == 0 {231			div232		} else {233			div + 1234		}235	}236}237238#[derive(Debug, Clone, Trace)]239#[force_tracking]240pub enum ArrValue {241	Bytes(#[skip_trace] Rc<[u8]>),242	Lazy(Cc<Vec<LazyVal>>),243	Eager(Cc<Vec<Val>>),244	Extended(Box<(Self, Self)>),245	Range(i32, i32),246	Slice(Box<Slice>),247	Reversed(Box<Self>),248}249impl ArrValue {250	pub fn new_eager() -> Self {251		Self::Eager(Cc::new(Vec::new()))252	}253254	/// # Panics255	/// If a > b256	pub fn new_range(a: i32, b: i32) -> Self {257		assert!(a <= b);258		Self::Range(a, b)259	}260261	/// # Panics262	/// If passed numbers are incorrect263	#[must_use]264	pub fn slice(self, from: Option<usize>, to: Option<usize>, step: Option<usize>) -> Self {265		let len = self.len();266		let from = from.unwrap_or(0);267		let to = to.unwrap_or(len).min(len);268		let step = step.unwrap_or(1);269		assert!(from < to);270		assert!(step > 0);271272		Self::Slice(Box::new(Slice {273			inner: self,274			from: from as u32,275			to: to as u32,276			step: step as u32,277		}))278	}279280	pub fn len(&self) -> usize {281		match self {282			Self::Bytes(i) => i.len(),283			Self::Lazy(l) => l.len(),284			Self::Eager(e) => e.len(),285			Self::Extended(v) => v.0.len() + v.1.len(),286			Self::Range(a, b) => a.abs_diff(*b) as usize + 1,287			Self::Reversed(i) => i.len(),288			Self::Slice(s) => s.len(),289		}290	}291292	pub fn is_empty(&self) -> bool {293		self.len() == 0294	}295296	pub fn get(&self, s: State, index: usize) -> Result<Option<Val>> {297		match self {298			Self::Bytes(i) => i299				.get(index)300				.map_or(Ok(None), |v| Ok(Some(Val::Num(f64::from(*v))))),301			Self::Lazy(vec) => {302				if let Some(v) = vec.get(index) {303					Ok(Some(v.evaluate(s)?))304				} else {305					Ok(None)306				}307			}308			Self::Eager(vec) => Ok(vec.get(index).cloned()),309			Self::Extended(v) => {310				let a_len = v.0.len();311				if a_len > index {312					v.0.get(s, index)313				} else {314					v.1.get(s, index - a_len)315				}316			}317			Self::Range(a, _) => {318				if index >= self.len() {319					return Ok(None);320				}321				Ok(Some(Val::Num(((*a as isize) + index as isize) as f64)))322			}323			Self::Reversed(v) => {324				let len = v.len();325				if index >= len {326					return Ok(None);327				}328				v.get(s, len - index - 1)329			}330			Self::Slice(v) => {331				let index = v.from() + index * v.step();332				if index >= v.to() {333					return Ok(None);334				}335				v.inner.get(s, index as usize)336			}337		}338	}339340	pub fn get_lazy(&self, index: usize) -> Option<LazyVal> {341		match self {342			Self::Bytes(i) => i343				.get(index)344				.map(|b| LazyVal::new_resolved(Val::Num(f64::from(*b)))),345			Self::Lazy(vec) => vec.get(index).cloned(),346			Self::Eager(vec) => vec.get(index).cloned().map(LazyVal::new_resolved),347			Self::Extended(v) => {348				let a_len = v.0.len();349				if a_len > index {350					v.0.get_lazy(index)351				} else {352					v.1.get_lazy(index - a_len)353				}354			}355			Self::Range(a, _) => {356				if index >= self.len() {357					return None;358				}359				Some(LazyVal::new_resolved(Val::Num(360					((*a as isize) + index as isize) as f64,361				)))362			}363			Self::Reversed(v) => {364				let len = v.len();365				if index >= len {366					return None;367				}368				v.get_lazy(len - index - 1)369			}370			Self::Slice(s) => {371				let index = s.from() + index * s.step();372				if index >= s.to() {373					return None;374				}375				s.inner.get_lazy(index as usize)376			}377		}378	}379380	pub fn evaluated(&self, s: State) -> Result<Cc<Vec<Val>>> {381		Ok(match self {382			Self::Bytes(i) => {383				let mut out = Vec::with_capacity(i.len());384				for v in i.iter() {385					out.push(Val::Num(f64::from(*v)));386				}387				Cc::new(out)388			}389			Self::Lazy(vec) => {390				let mut out = Vec::with_capacity(vec.len());391				for item in vec.iter() {392					out.push(item.evaluate(s.clone())?);393				}394				Cc::new(out)395			}396			Self::Eager(vec) => vec.clone(),397			Self::Extended(_v) => {398				let mut out = Vec::with_capacity(self.len());399				for item in self.iter(s) {400					out.push(item?);401				}402				Cc::new(out)403			}404			Self::Range(a, b) => {405				let mut out = Vec::with_capacity(self.len());406				for i in *a..*b {407					out.push(Val::Num(f64::from(i)));408				}409				Cc::new(out)410			}411			Self::Reversed(r) => {412				let mut r = r.evaluated(s)?;413				Cc::update_with(&mut r, |v| v.reverse());414				r415			}416			Self::Slice(v) => {417				let mut out = Vec::with_capacity(v.inner.len());418				for v in v419					.inner420					.iter_lazy()421					.skip(v.from())422					.take(v.to() - v.from())423					.step_by(v.step())424				{425					out.push(v.evaluate(s.clone())?);426				}427				Cc::new(out)428			}429		})430	}431432	pub fn iter(&self, s: State) -> impl DoubleEndedIterator<Item = Result<Val>> + '_ {433		(0..self.len()).map(move |idx| match self {434			Self::Bytes(b) => Ok(Val::Num(f64::from(b[idx]))),435			Self::Lazy(l) => l[idx].evaluate(s.clone()),436			Self::Eager(e) => Ok(e[idx].clone()),437			Self::Extended(..) | Self::Range(..) | Self::Reversed(..) | Self::Slice(..) => {438				self.get(s.clone(), idx).map(|e| e.expect("idx < len"))439			}440		})441	}442443	pub fn iter_lazy(&self) -> impl DoubleEndedIterator<Item = LazyVal> + '_ {444		(0..self.len()).map(move |idx| match self {445			Self::Bytes(b) => LazyVal::new_resolved(Val::Num(f64::from(b[idx]))),446			Self::Lazy(l) => l[idx].clone(),447			Self::Eager(e) => LazyVal::new_resolved(e[idx].clone()),448			Self::Slice(..) | Self::Extended(..) | Self::Range(..) | Self::Reversed(..) => {449				self.get_lazy(idx).expect("idx < len")450			}451		})452	}453454	#[must_use]455	pub fn reversed(self) -> Self {456		Self::Reversed(Box::new(self))457	}458459	pub fn map(self, s: State, mapper: impl Fn(Val) -> Result<Val>) -> Result<Self> {460		let mut out = Vec::with_capacity(self.len());461462		for value in self.iter(s) {463			out.push(mapper(value?)?);464		}465466		Ok(Self::Eager(Cc::new(out)))467	}468469	pub fn filter(self, s: State, filter: impl Fn(&Val) -> Result<bool>) -> Result<Self> {470		let mut out = Vec::with_capacity(self.len());471472		for value in self.iter(s) {473			let value = value?;474			if filter(&value)? {475				out.push(value);476			}477		}478479		Ok(Self::Eager(Cc::new(out)))480	}481482	pub fn ptr_eq(a: &Self, b: &Self) -> bool {483		match (a, b) {484			(Self::Lazy(a), Self::Lazy(b)) => cc_ptr_eq(a, b),485			(Self::Eager(a), Self::Eager(b)) => cc_ptr_eq(a, b),486			_ => false,487		}488	}489}490491impl From<Vec<LazyVal>> for ArrValue {492	fn from(v: Vec<LazyVal>) -> Self {493		Self::Lazy(Cc::new(v))494	}495}496497impl From<Vec<Val>> for ArrValue {498	fn from(v: Vec<Val>) -> Self {499		Self::Eager(Cc::new(v))500	}501}502503#[allow(clippy::module_name_repetitions)]504pub enum IndexableVal {505	Str(IStr),506	Arr(ArrValue),507}508509#[derive(Debug, Clone, Trace)]510pub enum Val {511	Bool(bool),512	Null,513	Str(IStr),514	Num(f64),515	Arr(ArrValue),516	Obj(ObjValue),517	Func(FuncVal),518}519520impl Val {521	pub const fn as_bool(&self) -> Option<bool> {522		match self {523			Val::Bool(v) => Some(*v),524			_ => None,525		}526	}527	pub const fn as_null(&self) -> Option<()> {528		match self {529			Val::Null => Some(()),530			_ => None,531		}532	}533	pub fn as_str(&self) -> Option<IStr> {534		match self {535			Val::Str(s) => Some(s.clone()),536			_ => None,537		}538	}539	pub const fn as_num(&self) -> Option<f64> {540		match self {541			Val::Num(n) => Some(*n),542			_ => None,543		}544	}545	pub fn as_arr(&self) -> Option<ArrValue> {546		match self {547			Val::Arr(a) => Some(a.clone()),548			_ => None,549		}550	}551	pub fn as_obj(&self) -> Option<ObjValue> {552		match self {553			Val::Obj(o) => Some(o.clone()),554			_ => None,555		}556	}557	pub fn as_func(&self) -> Option<FuncVal> {558		match self {559			Val::Func(f) => Some(f.clone()),560			_ => None,561		}562	}563564	/// Creates `Val::Num` after checking for numeric overflow.565	/// As numbers are `f64`, we can just check for their finity.566	pub fn new_checked_num(num: f64) -> Result<Self> {567		if num.is_finite() {568			Ok(Self::Num(num))569		} else {570			throw!(RuntimeError("overflow".into()))571		}572	}573574	pub const fn value_type(&self) -> ValType {575		match self {576			Self::Str(..) => ValType::Str,577			Self::Num(..) => ValType::Num,578			Self::Arr(..) => ValType::Arr,579			Self::Obj(..) => ValType::Obj,580			Self::Bool(_) => ValType::Bool,581			Self::Null => ValType::Null,582			Self::Func(..) => ValType::Func,583		}584	}585586	pub fn to_string(&self, s: State) -> Result<IStr> {587		Ok(match self {588			Self::Bool(true) => "true".into(),589			Self::Bool(false) => "false".into(),590			Self::Null => "null".into(),591			Self::Str(s) => s.clone(),592			v => manifest_json_ex(593				s,594				v,595				&ManifestJsonOptions {596					padding: "",597					mtype: ManifestType::ToString,598					newline: "\n",599					key_val_sep: ": ",600					#[cfg(feature = "exp-preserve-order")]601					preserve_order: false,602				},603			)?604			.into(),605		})606	}607608	/// Expects value to be object, outputs (key, manifested value) pairs609	pub fn manifest_multi(&self, s: State, ty: &ManifestFormat) -> Result<Vec<(IStr, IStr)>> {610		let obj = match self {611			Self::Obj(obj) => obj,612			_ => throw!(MultiManifestOutputIsNotAObject),613		};614		let keys = obj.fields(615			#[cfg(feature = "exp-preserve-order")]616			ty.preserve_order(),617		);618		let mut out = Vec::with_capacity(keys.len());619		for key in keys {620			let value = obj621				.get(s.clone(), key.clone())?622				.expect("item in object")623				.manifest(s.clone(), ty)?;624			out.push((key, value));625		}626		Ok(out)627	}628629	/// Expects value to be array, outputs manifested values630	pub fn manifest_stream(&self, s: State, ty: &ManifestFormat) -> Result<Vec<IStr>> {631		let arr = match self {632			Self::Arr(a) => a,633			_ => throw!(StreamManifestOutputIsNotAArray),634		};635		let mut out = Vec::with_capacity(arr.len());636		for i in arr.iter(s.clone()) {637			out.push(i?.manifest(s.clone(), ty)?);638		}639		Ok(out)640	}641642	pub fn manifest(&self, s: State, ty: &ManifestFormat) -> Result<IStr> {643		Ok(match ty {644			ManifestFormat::YamlStream(format) => {645				let arr = match self {646					Self::Arr(a) => a,647					_ => throw!(StreamManifestOutputIsNotAArray),648				};649				let mut out = String::new();650651				match format as &ManifestFormat {652					ManifestFormat::YamlStream(_) => throw!(StreamManifestOutputCannotBeRecursed),653					ManifestFormat::String => throw!(StreamManifestCannotNestString),654					_ => {}655				};656657				if !arr.is_empty() {658					for v in arr.iter(s.clone()) {659						out.push_str("---\n");660						out.push_str(&v?.manifest(s.clone(), format)?);661						out.push('\n');662					}663					out.push_str("...");664				}665666				out.into()667			}668			ManifestFormat::Yaml {669				padding,670				#[cfg(feature = "exp-preserve-order")]671				preserve_order,672			} => self.to_yaml(673				s,674				*padding,675				#[cfg(feature = "exp-preserve-order")]676				*preserve_order,677			)?,678			ManifestFormat::Json {679				padding,680				#[cfg(feature = "exp-preserve-order")]681				preserve_order,682			} => self.to_json(683				s,684				*padding,685				#[cfg(feature = "exp-preserve-order")]686				*preserve_order,687			)?,688			ManifestFormat::ToString => self.to_string(s)?,689			ManifestFormat::String => match self {690				Self::Str(s) => s.clone(),691				_ => throw!(StringManifestOutputIsNotAString),692			},693		})694	}695696	/// For manifestification697	pub fn to_json(698		&self,699		s: State,700		padding: usize,701		#[cfg(feature = "exp-preserve-order")] preserve_order: bool,702	) -> Result<IStr> {703		manifest_json_ex(704			s,705			self,706			&ManifestJsonOptions {707				padding: &" ".repeat(padding),708				mtype: if padding == 0 {709					ManifestType::Minify710				} else {711					ManifestType::Manifest712				},713				newline: "\n",714				key_val_sep: ": ",715				#[cfg(feature = "exp-preserve-order")]716				preserve_order,717			},718		)719		.map(Into::into)720	}721722	/// Calls `std.manifestJson`723	pub fn to_std_json(724		&self,725		s: State,726		padding: usize,727		#[cfg(feature = "exp-preserve-order")] preserve_order: bool,728	) -> Result<Rc<str>> {729		manifest_json_ex(730			s,731			self,732			&ManifestJsonOptions {733				padding: &" ".repeat(padding),734				mtype: ManifestType::Std,735				newline: "\n",736				key_val_sep: ": ",737				#[cfg(feature = "exp-preserve-order")]738				preserve_order,739			},740		)741		.map(Into::into)742	}743744	pub fn to_yaml(745		&self,746		s: State,747		padding: usize,748		#[cfg(feature = "exp-preserve-order")] preserve_order: bool,749	) -> Result<IStr> {750		let padding = &" ".repeat(padding);751		manifest_yaml_ex(752			s,753			self,754			&ManifestYamlOptions {755				padding,756				arr_element_padding: padding,757				quote_keys: false,758				#[cfg(feature = "exp-preserve-order")]759				preserve_order,760			},761		)762		.map(Into::into)763	}764	pub fn into_indexable(self) -> Result<IndexableVal> {765		Ok(match self {766			Val::Str(s) => IndexableVal::Str(s),767			Val::Arr(arr) => IndexableVal::Arr(arr),768			_ => throw!(ValueIsNotIndexable(self.value_type())),769		})770	}771}772773const fn is_function_like(val: &Val) -> bool {774	matches!(val, Val::Func(_))775}776777/// Native implementation of `std.primitiveEquals`778pub fn primitive_equals(val_a: &Val, val_b: &Val) -> Result<bool> {779	Ok(match (val_a, val_b) {780		(Val::Bool(a), Val::Bool(b)) => a == b,781		(Val::Null, Val::Null) => true,782		(Val::Str(a), Val::Str(b)) => a == b,783		(Val::Num(a), Val::Num(b)) => (a - b).abs() <= f64::EPSILON,784		(Val::Arr(_), Val::Arr(_)) => throw!(RuntimeError(785			"primitiveEquals operates on primitive types, got array".into(),786		)),787		(Val::Obj(_), Val::Obj(_)) => throw!(RuntimeError(788			"primitiveEquals operates on primitive types, got object".into(),789		)),790		(a, b) if is_function_like(a) && is_function_like(b) => {791			throw!(RuntimeError("cannot test equality of functions".into()))792		}793		(_, _) => false,794	})795}796797/// Native implementation of `std.equals`798pub fn equals(s: State, val_a: &Val, val_b: &Val) -> Result<bool> {799	if val_a.value_type() != val_b.value_type() {800		return Ok(false);801	}802	match (val_a, val_b) {803		(Val::Arr(a), Val::Arr(b)) => {804			if ArrValue::ptr_eq(a, b) {805				return Ok(true);806			}807			if a.len() != b.len() {808				return Ok(false);809			}810			for (a, b) in a.iter(s.clone()).zip(b.iter(s.clone())) {811				if !equals(s.clone(), &a?, &b?)? {812					return Ok(false);813				}814			}815			Ok(true)816		}817		(Val::Obj(a), Val::Obj(b)) => {818			if ObjValue::ptr_eq(a, b) {819				return Ok(true);820			}821			let fields = a.fields(822				#[cfg(feature = "exp-preserve-order")]823				false,824			);825			if fields826				!= b.fields(827					#[cfg(feature = "exp-preserve-order")]828					false,829				) {830				return Ok(false);831			}832			for field in fields {833				if !equals(834					s.clone(),835					&a.get(s.clone(), field.clone())?.expect("field exists"),836					&b.get(s.clone(), field)?.expect("field exists"),837				)? {838					return Ok(false);839				}840			}841			Ok(true)842		}843		(a, b) => Ok(primitive_equals(a, b)?),844	}845}