git.delta.rocks / jrsonnet / refs/commits / 321e7ee3e21c

difftreelog

source

crates/jrsonnet-evaluator/src/val.rs19.3 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#[derive(Clone, Trace)]36pub struct LazyVal(Cc<RefCell<LazyValInternals>>);37impl LazyVal {38	pub fn new(f: TraceBox<dyn LazyValValue>) -> Self {39		Self(Cc::new(RefCell::new(LazyValInternals::Waiting(f))))40	}41	pub fn new_resolved(val: Val) -> Self {42		Self(Cc::new(RefCell::new(LazyValInternals::Computed(val))))43	}44	pub fn force(&self, s: State) -> Result<()> {45		self.evaluate(s)?;46		Ok(())47	}48	pub fn evaluate(&self, s: State) -> Result<Val> {49		match &*self.0.borrow() {50			LazyValInternals::Computed(v) => return Ok(v.clone()),51			LazyValInternals::Errored(e) => return Err(e.clone()),52			LazyValInternals::Pending => return Err(InfiniteRecursionDetected.into()),53			_ => (),54		};55		let value = if let LazyValInternals::Waiting(value) =56			std::mem::replace(&mut *self.0.borrow_mut(), LazyValInternals::Pending)57		{58			value59		} else {60			unreachable!()61		};62		let new_value = match value.0.get(s) {63			Ok(v) => v,64			Err(e) => {65				*self.0.borrow_mut() = LazyValInternals::Errored(e.clone());66				return Err(e);67			}68		};69		*self.0.borrow_mut() = LazyValInternals::Computed(new_value.clone());70		Ok(new_value)71	}72}7374impl Debug for LazyVal {75	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {76		write!(f, "Lazy")77	}78}79impl PartialEq for LazyVal {80	fn eq(&self, other: &Self) -> bool {81		cc_ptr_eq(&self.0, &other.0)82	}83}8485#[derive(Debug, PartialEq, Trace)]86pub struct FuncDesc {87	pub name: IStr,88	pub ctx: Context,89	pub params: ParamsDesc,90	pub body: LocExpr,91}92impl FuncDesc {93	/// Create body context, but fill arguments without defaults with lazy error94	pub fn default_body_context(&self) -> Context {95		parse_default_function_call(self.ctx.clone(), &self.params)96	}9798	/// Create context, with which body code will run99	pub fn call_body_context(100		&self,101		s: State,102		call_ctx: Context,103		args: &dyn ArgsLike,104		tailstrict: bool,105	) -> Result<Context> {106		parse_function_call(107			s,108			call_ctx,109			self.ctx.clone(),110			&self.params,111			args,112			tailstrict,113		)114	}115}116117#[derive(Trace, Clone)]118pub enum FuncVal {119	/// Plain function implemented in jsonnet120	Normal(Cc<FuncDesc>),121	/// Standard library function122	StaticBuiltin(#[skip_trace] &'static dyn StaticBuiltin),123	/// User-provided function124	Builtin(Cc<TraceBox<dyn Builtin>>),125}126127impl Debug for FuncVal {128	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {129		match self {130			Self::Normal(arg0) => f.debug_tuple("Normal").field(arg0).finish(),131			Self::StaticBuiltin(arg0) => {132				f.debug_tuple("StaticBuiltin").field(&arg0.name()).finish()133			}134			Self::Builtin(arg0) => f.debug_tuple("Builtin").field(&arg0.name()).finish(),135		}136	}137}138139impl FuncVal {140	pub fn args_len(&self) -> usize {141		match self {142			Self::Normal(n) => n.params.iter().filter(|p| p.1.is_none()).count(),143			Self::StaticBuiltin(i) => i.params().iter().filter(|p| !p.has_default).count(),144			Self::Builtin(i) => i.params().iter().filter(|p| !p.has_default).count(),145		}146	}147	pub fn name(&self) -> IStr {148		match self {149			Self::Normal(normal) => normal.name.clone(),150			Self::StaticBuiltin(builtin) => builtin.name().into(),151			Self::Builtin(builtin) => builtin.name().into(),152		}153	}154	pub fn evaluate(155		&self,156		s: State,157		call_ctx: Context,158		loc: CallLocation,159		args: &dyn ArgsLike,160		tailstrict: bool,161	) -> Result<Val> {162		match self {163			Self::Normal(func) => {164				let body_ctx = func.call_body_context(s.clone(), call_ctx, args, tailstrict)?;165				evaluate(s, body_ctx, &func.body)166			}167			Self::StaticBuiltin(b) => b.call(s, call_ctx, loc, args),168			Self::Builtin(b) => b.call(s, call_ctx, loc, args),169		}170	}171	pub fn evaluate_simple(&self, s: State, args: &dyn ArgsLike) -> Result<Val> {172		self.evaluate(s, Context::default(), CallLocation::native(), args, true)173	}174}175176#[derive(Clone)]177pub enum ManifestFormat {178	YamlStream(Box<ManifestFormat>),179	Yaml {180		padding: usize,181		#[cfg(feature = "exp-preserve-order")]182		preserve_order: bool,183	},184	Json {185		padding: usize,186		#[cfg(feature = "exp-preserve-order")]187		preserve_order: bool,188	},189	ToString,190	String,191}192impl ManifestFormat {193	#[cfg(feature = "exp-preserve-order")]194	fn preserve_order(&self) -> bool {195		match self {196			ManifestFormat::YamlStream(s) => s.preserve_order(),197			ManifestFormat::Yaml { preserve_order, .. } => *preserve_order,198			ManifestFormat::Json { preserve_order, .. } => *preserve_order,199			ManifestFormat::ToString => false,200			ManifestFormat::String => false,201		}202	}203}204205#[derive(Debug, Clone, Trace)]206pub struct Slice {207	pub(crate) inner: ArrValue,208	pub(crate) from: u32,209	pub(crate) to: u32,210	pub(crate) step: u32,211}212impl Slice {213	const fn from(&self) -> usize {214		self.from as usize215	}216	const fn to(&self) -> usize {217		self.to as usize218	}219	const fn step(&self) -> usize {220		self.step as usize221	}222	const fn len(&self) -> usize {223		// TODO: use div_ceil224		let diff = self.to() - self.from();225		let rem = diff % self.step();226		let div = diff / self.step();227228		if rem != 0 {229			div + 1230		} else {231			div232		}233	}234}235236#[derive(Debug, Clone, Trace)]237#[force_tracking]238pub enum ArrValue {239	Bytes(#[skip_trace] Rc<[u8]>),240	Lazy(Cc<Vec<LazyVal>>),241	Eager(Cc<Vec<Val>>),242	Extended(Box<(Self, Self)>),243	Range(i32, i32),244	Slice(Box<Slice>),245	Reversed(Box<Self>),246}247impl ArrValue {248	pub fn new_eager() -> Self {249		Self::Eager(Cc::new(Vec::new()))250	}251	pub fn new_range(a: i32, b: i32) -> Self {252		assert!(a <= b);253		Self::Range(a, b)254	}255256	pub fn slice(self, from: Option<usize>, to: Option<usize>, step: Option<usize>) -> Self {257		let len = self.len();258		let from = from.unwrap_or(0);259		let to = to.unwrap_or(len).min(len);260		let step = step.unwrap_or(1);261		assert!(from < to);262		assert!(step > 0);263264		Self::Slice(Box::new(Slice {265			inner: self,266			from: from as u32,267			to: to as u32,268			step: step as u32,269		}))270	}271272	pub fn len(&self) -> usize {273		match self {274			Self::Bytes(i) => i.len(),275			Self::Lazy(l) => l.len(),276			Self::Eager(e) => e.len(),277			Self::Extended(v) => v.0.len() + v.1.len(),278			Self::Range(a, b) => a.abs_diff(*b) as usize + 1,279			Self::Reversed(i) => i.len(),280			Self::Slice(s) => s.len(),281		}282	}283284	pub fn is_empty(&self) -> bool {285		self.len() == 0286	}287288	pub fn get(&self, s: State, index: usize) -> Result<Option<Val>> {289		match self {290			Self::Bytes(i) => i291				.get(index)292				.map_or(Ok(None), |v| Ok(Some(Val::Num(*v as f64)))),293			Self::Lazy(vec) => {294				if let Some(v) = vec.get(index) {295					Ok(Some(v.evaluate(s)?))296				} else {297					Ok(None)298				}299			}300			Self::Eager(vec) => Ok(vec.get(index).cloned()),301			Self::Extended(v) => {302				let a_len = v.0.len();303				if a_len > index {304					v.0.get(s, index)305				} else {306					v.1.get(s, index - a_len)307				}308			}309			Self::Range(a, _) => {310				if index >= self.len() {311					return Ok(None);312				}313				Ok(Some(Val::Num(((*a as isize) + index as isize) as f64)))314			}315			Self::Reversed(v) => {316				let len = v.len();317				if index >= len {318					return Ok(None);319				}320				v.get(s, len - index - 1)321			}322			Self::Slice(v) => {323				let index = v.from() + index * v.step();324				if index >= v.to() {325					return Ok(None);326				}327				v.inner.get(s, index as usize)328			}329		}330	}331332	pub fn get_lazy(&self, index: usize) -> Option<LazyVal> {333		match self {334			Self::Bytes(i) => i335				.get(index)336				.map(|b| LazyVal::new_resolved(Val::Num(*b as f64))),337			Self::Lazy(vec) => vec.get(index).cloned(),338			Self::Eager(vec) => vec.get(index).cloned().map(LazyVal::new_resolved),339			Self::Extended(v) => {340				let a_len = v.0.len();341				if a_len > index {342					v.0.get_lazy(index)343				} else {344					v.1.get_lazy(index - a_len)345				}346			}347			Self::Range(a, _) => {348				if index >= self.len() {349					return None;350				}351				Some(LazyVal::new_resolved(Val::Num(352					((*a as isize) + index as isize) as f64,353				)))354			}355			Self::Reversed(v) => {356				let len = v.len();357				if index >= len {358					return None;359				}360				v.get_lazy(len - index - 1)361			}362			Self::Slice(s) => {363				let index = s.from() + index * s.step();364				if index >= s.to() {365					return None;366				}367				s.inner.get_lazy(index as usize)368			}369		}370	}371372	pub fn evaluated(&self, s: State) -> Result<Cc<Vec<Val>>> {373		Ok(match self {374			Self::Bytes(i) => {375				let mut out = Vec::with_capacity(i.len());376				for v in i.iter() {377					out.push(Val::Num(*v as f64));378				}379				Cc::new(out)380			}381			Self::Lazy(vec) => {382				let mut out = Vec::with_capacity(vec.len());383				for item in vec.iter() {384					out.push(item.evaluate(s.clone())?);385				}386				Cc::new(out)387			}388			Self::Eager(vec) => vec.clone(),389			Self::Extended(_v) => {390				let mut out = Vec::with_capacity(self.len());391				for item in self.iter(s) {392					out.push(item?);393				}394				Cc::new(out)395			}396			Self::Range(a, b) => {397				let mut out = Vec::with_capacity(self.len());398				for i in *a..*b {399					out.push(Val::Num(i as f64));400				}401				Cc::new(out)402			}403			Self::Reversed(r) => {404				let mut r = r.evaluated(s)?;405				Cc::update_with(&mut r, |v| v.reverse());406				r407			}408			Self::Slice(v) => {409				let mut out = Vec::with_capacity(v.inner.len());410				for v in v411					.inner412					.iter_lazy()413					.skip(v.from())414					.take(v.to() - v.from())415					.step_by(v.step())416				{417					out.push(v.evaluate(s.clone())?)418				}419				Cc::new(out)420			}421		})422	}423424	pub fn iter(&self, s: State) -> impl DoubleEndedIterator<Item = Result<Val>> + '_ {425		(0..self.len()).map(move |idx| match self {426			Self::Bytes(b) => Ok(Val::Num(b[idx] as f64)),427			Self::Lazy(l) => l[idx].evaluate(s.clone()),428			Self::Eager(e) => Ok(e[idx].clone()),429			Self::Extended(_) => self.get(s.clone(), idx).map(|e| e.unwrap()),430			Self::Range(..) => self.get(s.clone(), idx).map(|e| e.unwrap()),431			Self::Reversed(..) => self.get(s.clone(), idx).map(|e| e.unwrap()),432			Self::Slice(..) => self.get(s.clone(), idx).map(|e| e.unwrap()),433		})434	}435436	pub fn iter_lazy(&self) -> impl DoubleEndedIterator<Item = LazyVal> + '_ {437		(0..self.len()).map(move |idx| match self {438			Self::Bytes(b) => LazyVal::new_resolved(Val::Num(b[idx] as f64)),439			Self::Lazy(l) => l[idx].clone(),440			Self::Eager(e) => LazyVal::new_resolved(e[idx].clone()),441			Self::Extended(_) => self.get_lazy(idx).unwrap(),442			Self::Range(..) => self.get_lazy(idx).unwrap(),443			Self::Reversed(..) => self.get_lazy(idx).unwrap(),444			Self::Slice(..) => self.get_lazy(idx).unwrap(),445		})446	}447448	pub fn reversed(self) -> Self {449		Self::Reversed(Box::new(self))450	}451452	pub fn map(self, s: State, mapper: impl Fn(Val) -> Result<Val>) -> Result<Self> {453		let mut out = Vec::with_capacity(self.len());454455		for value in self.iter(s) {456			out.push(mapper(value?)?);457		}458459		Ok(Self::Eager(Cc::new(out)))460	}461462	pub fn filter(self, s: State, filter: impl Fn(&Val) -> Result<bool>) -> Result<Self> {463		let mut out = Vec::with_capacity(self.len());464465		for value in self.iter(s) {466			let value = value?;467			if filter(&value)? {468				out.push(value);469			}470		}471472		Ok(Self::Eager(Cc::new(out)))473	}474475	pub fn ptr_eq(a: &Self, b: &Self) -> bool {476		match (a, b) {477			(Self::Lazy(a), Self::Lazy(b)) => cc_ptr_eq(a, b),478			(Self::Eager(a), Self::Eager(b)) => cc_ptr_eq(a, b),479			_ => false,480		}481	}482}483484impl From<Vec<LazyVal>> for ArrValue {485	fn from(v: Vec<LazyVal>) -> Self {486		Self::Lazy(Cc::new(v))487	}488}489490impl From<Vec<Val>> for ArrValue {491	fn from(v: Vec<Val>) -> Self {492		Self::Eager(Cc::new(v))493	}494}495496pub enum IndexableVal {497	Str(IStr),498	Arr(ArrValue),499}500501#[derive(Debug, Clone, Trace)]502pub enum Val {503	Bool(bool),504	Null,505	Str(IStr),506	Num(f64),507	Arr(ArrValue),508	Obj(ObjValue),509	Func(FuncVal),510}511512impl Val {513	pub const fn as_bool(&self) -> Option<bool> {514		match self {515			Val::Bool(v) => Some(*v),516			_ => None,517		}518	}519	pub const fn as_null(&self) -> Option<()> {520		match self {521			Val::Null => Some(()),522			_ => None,523		}524	}525	pub fn as_str(&self) -> Option<IStr> {526		match self {527			Val::Str(s) => Some(s.clone()),528			_ => None,529		}530	}531	pub const fn as_num(&self) -> Option<f64> {532		match self {533			Val::Num(n) => Some(*n),534			_ => None,535		}536	}537	pub fn as_arr(&self) -> Option<ArrValue> {538		match self {539			Val::Arr(a) => Some(a.clone()),540			_ => None,541		}542	}543	pub fn as_obj(&self) -> Option<ObjValue> {544		match self {545			Val::Obj(o) => Some(o.clone()),546			_ => None,547		}548	}549	pub fn as_func(&self) -> Option<FuncVal> {550		match self {551			Val::Func(f) => Some(f.clone()),552			_ => None,553		}554	}555556	/// Creates `Val::Num` after checking for numeric overflow.557	/// As numbers are `f64`, we can just check for their finity.558	pub fn new_checked_num(num: f64) -> Result<Self> {559		if num.is_finite() {560			Ok(Self::Num(num))561		} else {562			throw!(RuntimeError("overflow".into()))563		}564	}565566	pub const fn value_type(&self) -> ValType {567		match self {568			Self::Str(..) => ValType::Str,569			Self::Num(..) => ValType::Num,570			Self::Arr(..) => ValType::Arr,571			Self::Obj(..) => ValType::Obj,572			Self::Bool(_) => ValType::Bool,573			Self::Null => ValType::Null,574			Self::Func(..) => ValType::Func,575		}576	}577578	pub fn to_string(&self, s: State) -> Result<IStr> {579		Ok(match self {580			Self::Bool(true) => "true".into(),581			Self::Bool(false) => "false".into(),582			Self::Null => "null".into(),583			Self::Str(s) => s.clone(),584			v => manifest_json_ex(585				s,586				v,587				&ManifestJsonOptions {588					padding: "",589					mtype: ManifestType::ToString,590					newline: "\n",591					key_val_sep: ": ",592					#[cfg(feature = "exp-preserve-order")]593					preserve_order: false,594				},595			)?596			.into(),597		})598	}599600	/// Expects value to be object, outputs (key, manifested value) pairs601	pub fn manifest_multi(&self, s: State, ty: &ManifestFormat) -> Result<Vec<(IStr, IStr)>> {602		let obj = match self {603			Self::Obj(obj) => obj,604			_ => throw!(MultiManifestOutputIsNotAObject),605		};606		let keys = obj.fields(607			#[cfg(feature = "exp-preserve-order")]608			ty.preserve_order(),609		);610		let mut out = Vec::with_capacity(keys.len());611		for key in keys {612			let value = obj613				.get(s.clone(), key.clone())?614				.expect("item in object")615				.manifest(s.clone(), ty)?;616			out.push((key, value));617		}618		Ok(out)619	}620621	/// Expects value to be array, outputs manifested values622	pub fn manifest_stream(&self, s: State, ty: &ManifestFormat) -> Result<Vec<IStr>> {623		let arr = match self {624			Self::Arr(a) => a,625			_ => throw!(StreamManifestOutputIsNotAArray),626		};627		let mut out = Vec::with_capacity(arr.len());628		for i in arr.iter(s.clone()) {629			out.push(i?.manifest(s.clone(), ty)?);630		}631		Ok(out)632	}633634	pub fn manifest(&self, s: State, ty: &ManifestFormat) -> Result<IStr> {635		Ok(match ty {636			ManifestFormat::YamlStream(format) => {637				let arr = match self {638					Self::Arr(a) => a,639					_ => throw!(StreamManifestOutputIsNotAArray),640				};641				let mut out = String::new();642643				match format as &ManifestFormat {644					ManifestFormat::YamlStream(_) => throw!(StreamManifestOutputCannotBeRecursed),645					ManifestFormat::String => throw!(StreamManifestCannotNestString),646					_ => {}647				};648649				if !arr.is_empty() {650					for v in arr.iter(s.clone()) {651						out.push_str("---\n");652						out.push_str(&v?.manifest(s.clone(), format)?);653						out.push('\n');654					}655					out.push_str("...");656				}657658				out.into()659			}660			ManifestFormat::Yaml {661				padding,662				#[cfg(feature = "exp-preserve-order")]663				preserve_order,664			} => self.to_yaml(665				s,666				*padding,667				#[cfg(feature = "exp-preserve-order")]668				*preserve_order,669			)?,670			ManifestFormat::Json {671				padding,672				#[cfg(feature = "exp-preserve-order")]673				preserve_order,674			} => self.to_json(675				s,676				*padding,677				#[cfg(feature = "exp-preserve-order")]678				*preserve_order,679			)?,680			ManifestFormat::ToString => self.to_string(s)?,681			ManifestFormat::String => match self {682				Self::Str(s) => s.clone(),683				_ => throw!(StringManifestOutputIsNotAString),684			},685		})686	}687688	/// For manifestification689	pub fn to_json(690		&self,691		s: State,692		padding: usize,693		#[cfg(feature = "exp-preserve-order")] preserve_order: bool,694	) -> Result<IStr> {695		manifest_json_ex(696			s,697			self,698			&ManifestJsonOptions {699				padding: &" ".repeat(padding),700				mtype: if padding == 0 {701					ManifestType::Minify702				} else {703					ManifestType::Manifest704				},705				newline: "\n",706				key_val_sep: ": ",707				#[cfg(feature = "exp-preserve-order")]708				preserve_order,709			},710		)711		.map(|s| s.into())712	}713714	/// Calls `std.manifestJson`715	pub fn to_std_json(716		&self,717		s: State,718		padding: usize,719		#[cfg(feature = "exp-preserve-order")] preserve_order: bool,720	) -> Result<Rc<str>> {721		manifest_json_ex(722			s,723			self,724			&ManifestJsonOptions {725				padding: &" ".repeat(padding),726				mtype: ManifestType::Std,727				newline: "\n",728				key_val_sep: ": ",729				#[cfg(feature = "exp-preserve-order")]730				preserve_order,731			},732		)733		.map(|s| s.into())734	}735736	pub fn to_yaml(737		&self,738		s: State,739		padding: usize,740		#[cfg(feature = "exp-preserve-order")] preserve_order: bool,741	) -> Result<IStr> {742		let padding = &" ".repeat(padding);743		manifest_yaml_ex(744			s,745			self,746			&ManifestYamlOptions {747				padding,748				arr_element_padding: padding,749				quote_keys: false,750				#[cfg(feature = "exp-preserve-order")]751				preserve_order,752			},753		)754		.map(|s| s.into())755	}756	pub fn into_indexable(self) -> Result<IndexableVal> {757		Ok(match self {758			Val::Str(s) => IndexableVal::Str(s),759			Val::Arr(arr) => IndexableVal::Arr(arr),760			_ => throw!(ValueIsNotIndexable(self.value_type())),761		})762	}763}764765const fn is_function_like(val: &Val) -> bool {766	matches!(val, Val::Func(_))767}768769/// Native implementation of `std.primitiveEquals`770pub fn primitive_equals(val_a: &Val, val_b: &Val) -> Result<bool> {771	Ok(match (val_a, val_b) {772		(Val::Bool(a), Val::Bool(b)) => a == b,773		(Val::Null, Val::Null) => true,774		(Val::Str(a), Val::Str(b)) => a == b,775		(Val::Num(a), Val::Num(b)) => (a - b).abs() <= f64::EPSILON,776		(Val::Arr(_), Val::Arr(_)) => throw!(RuntimeError(777			"primitiveEquals operates on primitive types, got array".into(),778		)),779		(Val::Obj(_), Val::Obj(_)) => throw!(RuntimeError(780			"primitiveEquals operates on primitive types, got object".into(),781		)),782		(a, b) if is_function_like(a) && is_function_like(b) => {783			throw!(RuntimeError("cannot test equality of functions".into()))784		}785		(_, _) => false,786	})787}788789/// Native implementation of `std.equals`790pub fn equals(s: State, val_a: &Val, val_b: &Val) -> Result<bool> {791	if val_a.value_type() != val_b.value_type() {792		return Ok(false);793	}794	match (val_a, val_b) {795		(Val::Arr(a), Val::Arr(b)) => {796			if ArrValue::ptr_eq(a, b) {797				return Ok(true);798			}799			if a.len() != b.len() {800				return Ok(false);801			}802			for (a, b) in a.iter(s.clone()).zip(b.iter(s.clone())) {803				if !equals(s.clone(), &a?, &b?)? {804					return Ok(false);805				}806			}807			Ok(true)808		}809		(Val::Obj(a), Val::Obj(b)) => {810			if ObjValue::ptr_eq(a, b) {811				return Ok(true);812			}813			let fields = a.fields(814				#[cfg(feature = "exp-preserve-order")]815				false,816			);817			if fields818				!= b.fields(819					#[cfg(feature = "exp-preserve-order")]820					false,821				) {822				return Ok(false);823			}824			for field in fields {825				if !equals(826					s.clone(),827					&a.get(s.clone(), field.clone())?.unwrap(),828					&b.get(s.clone(), field)?.unwrap(),829				)? {830					return Ok(false);831				}832			}833			Ok(true)834		}835		(a, b) => Ok(primitive_equals(a, b)?),836	}837}