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

difftreelog

style fix clippy warnings

Yaroslav Bolyukin2022-04-20parent: #ed4ee4d.patch.diff
in: master

5 files changed

modifiedcrates/jrsonnet-evaluator/src/function.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/function.rs
+++ b/crates/jrsonnet-evaluator/src/function.rs
@@ -15,12 +15,12 @@
 #[derive(Clone, Copy)]
 pub struct CallLocation<'l>(pub Option<&'l ExprLocation>);
 impl<'l> CallLocation<'l> {
-	pub fn new(loc: &'l ExprLocation) -> Self {
+	pub const fn new(loc: &'l ExprLocation) -> Self {
 		Self(Some(loc))
 	}
 }
 impl CallLocation<'static> {
-	pub fn native() -> Self {
+	pub const fn native() -> Self {
 		Self(None)
 	}
 }
modifiedcrates/jrsonnet-evaluator/src/integrations/serde.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/integrations/serde.rs
+++ b/crates/jrsonnet-evaluator/src/integrations/serde.rs
@@ -20,7 +20,7 @@
 			Val::Arr(a) => {
 				let mut out = Vec::with_capacity(a.len());
 				for item in a.iter() {
-					out.push((&item?).try_into()?);
+					out.push(item?.try_into()?);
 				}
 				Self::Array(out)
 			}
@@ -29,8 +29,8 @@
 				for key in o.fields() {
 					out.insert(
 						(&key as &str).into(),
-						(&o.get(key)?
-							.expect("key is present in fields, so value should exist"))
+						o.get(key)?
+							.expect("key is present in fields, so value should exist")
 							.try_into()?,
 					);
 				}
@@ -40,6 +40,13 @@
 		})
 	}
 }
+impl TryFrom<Val> for Value {
+	type Error = LocError;
+
+	fn try_from(value: Val) -> Result<Self, Self::Error> {
+		<Self as TryFrom<&Val>>::try_from(&value)
+	}
+}
 
 impl TryFrom<&Value> for Val {
 	type Error = LocError;
@@ -68,3 +75,10 @@
 		})
 	}
 }
+impl TryFrom<Value> for Val {
+	type Error = LocError;
+
+	fn try_from(value: Value) -> Result<Self, Self::Error> {
+		<Self as TryFrom<&Value>>::try_from(&value)
+	}
+}
modifiedcrates/jrsonnet-evaluator/src/typed/conversions.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/typed/conversions.rs
+++ b/crates/jrsonnet-evaluator/src/typed/conversions.rs
@@ -442,7 +442,7 @@
 	fn try_from(value: Val) -> Result<Self, Self::Error> {
 		<Self as Typed>::TYPE.check(&value)?;
 		match value {
-			Val::Func(FuncVal::Normal(desc)) => Ok(desc.clone()),
+			Val::Func(FuncVal::Normal(desc)) => Ok(desc),
 			Val::Func(_) => throw!(RuntimeError("expected normal function, not builtin".into())),
 			_ => unreachable!(),
 		}
modifiedcrates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/val.rs
+++ b/crates/jrsonnet-evaluator/src/val.rs
@@ -126,15 +126,6 @@
 	}
 }
 
-impl PartialEq for FuncVal {
-	fn eq(&self, other: &Self) -> bool {
-		match (self, other) {
-			(Self::Normal(a), Self::Normal(b)) => a == b,
-			(Self::StaticBuiltin(an), Self::StaticBuiltin(bn)) => std::ptr::eq(*an, *bn),
-			(..) => false,
-		}
-	}
-}
 impl FuncVal {
 	pub fn args_len(&self) -> usize {
 		match self {
@@ -353,13 +344,13 @@
 }
 
 impl Val {
-	pub fn as_bool(&self) -> Option<bool> {
+	pub const fn as_bool(&self) -> Option<bool> {
 		match self {
 			Val::Bool(v) => Some(*v),
 			_ => None,
 		}
 	}
-	pub fn as_null(&self) -> Option<()> {
+	pub const fn as_null(&self) -> Option<()> {
 		match self {
 			Val::Null => Some(()),
 			_ => None,
@@ -371,7 +362,7 @@
 			_ => None,
 		}
 	}
-	pub fn as_num(&self) -> Option<f64> {
+	pub const fn as_num(&self) -> Option<f64> {
 		match self {
 			Val::Num(n) => Some(*n),
 			_ => None,
modifiedcrates/jrsonnet-macros/src/lib.rsdiffbeforeafterboth
before · crates/jrsonnet-macros/src/lib.rs
1use proc_macro2::TokenStream;2use quote::quote;3use syn::{4	parenthesized,5	parse::{Parse, ParseStream},6	parse_macro_input,7	punctuated::Punctuated,8	spanned::Spanned,9	token::Comma,10	Attribute, DeriveInput, Error, FnArg, GenericArgument, Ident, ItemFn, LitStr, Pat, Path,11	PathArguments, Result, ReturnType, Token, Type,12};1314fn parse_attr<A: Parse, I>(attrs: &[Attribute], ident: I) -> Result<Option<A>>15where16	Ident: PartialEq<I>,17{18	let attrs = attrs19		.iter()20		.filter(|a| a.path.is_ident(&ident))21		.collect::<Vec<_>>();22	if attrs.len() > 1 {23		return Err(Error::new(24			attrs[1].span(),25			"this attribute may be specified only once",26		));27	} else if attrs.is_empty() {28		return Ok(None);29	}30	let attr = attrs[0];31	let attr = attr.parse_args::<A>()?;3233	Ok(Some(attr))34}3536fn path_is(path: &Path, needed: &str) -> bool {37	path.leading_colon.is_none()38		&& path.segments.len() >= 139		&& path.segments.iter().last().unwrap().ident == needed40}4142fn type_is_path<'ty>(ty: &'ty Type, needed: &str) -> Option<&'ty PathArguments> {43	match ty {44		Type::Path(path) if path.qself.is_none() && path_is(&path.path, needed) => {45			let args = &path.path.segments.iter().last().unwrap().arguments;46			Some(args)47		}48		_ => None,49	}50}5152fn extract_type_from_option(ty: &Type) -> Result<Option<&Type>> {53	Ok(if let Some(args) = type_is_path(ty, "Option") {54		// It should have only on angle-bracketed param ("<String>"):55		let generic_arg = match args {56			PathArguments::AngleBracketed(params) => params.args.iter().next().unwrap(),57			_ => return Err(Error::new(args.span(), "missing option generic")),58		};59		// This argument must be a type:60		match generic_arg {61			GenericArgument::Type(ty) => Some(ty),62			_ => {63				return Err(Error::new(64					generic_arg.span(),65					"option generic should be a type",66				))67			}68		}69	} else {70		None71	})72}7374struct Field {75	name: Ident,76	_colon: Token![:],77	ty: Type,78}79impl Parse for Field {80	fn parse(input: ParseStream) -> syn::Result<Self> {81		Ok(Self {82			name: input.parse()?,83			_colon: input.parse()?,84			ty: input.parse()?,85		})86	}87}8889mod kw {90	syn::custom_keyword!(fields);91	syn::custom_keyword!(rename);92	syn::custom_keyword!(flatten);93}9495struct EmptyAttr;96impl Parse for EmptyAttr {97	fn parse(_input: ParseStream) -> Result<Self> {98		Ok(Self)99	}100}101102struct BuiltinAttrs {103	fields: Vec<Field>,104}105impl Parse for BuiltinAttrs {106	fn parse(input: ParseStream) -> syn::Result<Self> {107		if input.is_empty() {108			return Ok(Self { fields: Vec::new() });109		}110		input.parse::<kw::fields>()?;111		let fields;112		parenthesized!(fields in input);113		let p = Punctuated::<Field, Comma>::parse_terminated(&fields)?;114		Ok(Self {115			fields: p.into_iter().collect(),116		})117	}118}119120enum ArgInfo {121	Normal {122		ty: Type,123		is_option: bool,124		name: String,125		// ident: Ident,126	},127	Lazy {128		is_option: bool,129		name: String,130	},131	Location,132	This,133}134135impl ArgInfo {136	fn parse(arg: &FnArg) -> Result<Self> {137		let typed = match arg {138			FnArg::Receiver(_) => unreachable!(),139			FnArg::Typed(a) => a,140		};141		let ident = match &typed.pat as &Pat {142			Pat::Ident(i) => i.ident.clone(),143			_ => {144				return Err(Error::new(145					typed.pat.span(),146					"arg should be plain identifier",147				))148			}149		};150		let ty = &typed.ty as &Type;151		if type_is_path(&ty, "CallLocation").is_some() {152			return Ok(Self::Location);153		} else if type_is_path(&ty, "Self").is_some() {154			return Ok(Self::This);155		} else if type_is_path(&ty, "LazyVal").is_some() {156			return Ok(Self::Lazy {157				is_option: false,158				name: ident.to_string(),159			});160		}161162		let (is_option, ty) = if let Some(ty) = extract_type_from_option(&ty)? {163			if type_is_path(&ty, "LazyVal").is_some() {164				return Ok(Self::Lazy {165					is_option: true,166					name: ident.to_string(),167				});168			}169170			(true, ty.clone())171		} else {172			(false, ty.clone())173		};174175		Ok(Self::Normal {176			ty,177			is_option,178			name: ident.to_string(),179			// ident,180		})181	}182}183184#[proc_macro_attribute]185pub fn builtin(186	attr: proc_macro::TokenStream,187	item: proc_macro::TokenStream,188) -> proc_macro::TokenStream {189	let attr = parse_macro_input!(attr as BuiltinAttrs);190	let item: ItemFn = parse_macro_input!(item);191192	match builtin_inner(attr, item) {193		Ok(v) => v.into(),194		Err(e) => e.into_compile_error().into(),195	}196}197198fn builtin_inner(attr: BuiltinAttrs, fun: ItemFn) -> syn::Result<TokenStream> {199	let result = match fun.sig.output {200		ReturnType::Default => {201			return Err(Error::new(202				fun.sig.span(),203				"builtin should return something",204			))205		}206		ReturnType::Type(_, ref ty) => ty.clone(),207	};208209	let args = fun210		.sig211		.inputs212		.iter()213		.map(|a| ArgInfo::parse(a))214		.collect::<Result<Vec<_>>>()?;215216	let params_desc = args.iter().flat_map(|a| match a {217		ArgInfo::Normal {218			is_option, name, ..219		}220		| ArgInfo::Lazy { is_option, name } => Some(quote! {221			BuiltinParam {222				name: std::borrow::Cow::Borrowed(#name),223				has_default: #is_option,224			}225		}),226		ArgInfo::Location => None,227		ArgInfo::This => None,228	});229230	let pass = args.iter().map(|a| match a {231		ArgInfo::Normal {232			ty,233			is_option,234			name,235			// ident,236		} => {237			let eval = quote! {::jrsonnet_evaluator::push_description_frame(238				|| format!("argument <{}> evaluation", #name),239				|| <#ty>::try_from(value.evaluate()?),240			)?};241			if *is_option {242				quote! {if let Some(value) = parsed.get(#name) {243					Some(#eval)244				} else {245					None246				}}247			} else {248				quote! {{249					let value = parsed.get(#name).expect("args shape is checked");250					#eval251				}}252			}253		}254		ArgInfo::Lazy { is_option, name } => {255			if *is_option {256				quote! {if let Some(value) = parsed.get(#name) {257					Some(value.clone())258				} else {259					None260				}}261			} else {262				quote! {263					parsed.get(#name).expect("args shape is correct").clone()264				}265			}266		}267		ArgInfo::Location => quote! {location},268		ArgInfo::This => quote! {self},269	});270271	let fields = attr.fields.iter().map(|field| {272		let name = &field.name;273		let ty = &field.ty;274		quote! {275			pub #name: #ty,276		}277	});278279	let name = &fun.sig.ident;280	let vis = &fun.vis;281	let static_ext = if attr.fields.is_empty() {282		quote! {283			impl #name {284				pub const INST: &'static dyn StaticBuiltin = &#name {};285			}286			impl StaticBuiltin for #name {}287		}288	} else {289		quote! {}290	};291	let static_derive_copy = if attr.fields.is_empty() {292		quote! {, Copy}293	} else {294		quote! {}295	};296297	Ok(quote! {298		#fun299		#[doc(hidden)]300		#[allow(non_camel_case_types)]301		#[derive(Clone, gcmodule::Trace #static_derive_copy)]302		#vis struct #name {303			#(#fields)*304		}305		const _: () = {306			use ::jrsonnet_evaluator::{307				function::{Builtin, CallLocation, StaticBuiltin, BuiltinParam, ArgsLike, parse_builtin_call},308				error::Result, Context,309				parser::ExprLocation,310			};311			const PARAMS: &'static [BuiltinParam] = &[312				#(#params_desc),*313			];314315			#static_ext316			impl Builtin for #name317			where318				Self: 'static319			{320				fn name(&self) -> &str {321					stringify!(#name)322				}323				fn params(&self) -> &[BuiltinParam] {324					PARAMS325				}326				fn call(&self, context: Context, location: CallLocation, args: &dyn ArgsLike) -> Result<Val> {327					let parsed = parse_builtin_call(context, &PARAMS, args, false)?;328329					let result: #result = #name(#(#pass),*);330					let result = result?;331					result.try_into()332				}333			}334		};335	})336}337338#[derive(Default)]339struct TypedAttr {340	rename: Option<String>,341	flatten: bool,342}343impl Parse for TypedAttr {344	fn parse(input: ParseStream) -> syn::Result<Self> {345		let mut out = Self::default();346		loop {347			let lookahead = input.lookahead1();348			if lookahead.peek(kw::rename) {349				input.parse::<kw::rename>()?;350				input.parse::<Token![=]>()?;351				let name = input.parse::<LitStr>()?;352				if out.rename.is_some() {353					return Err(Error::new(354						name.span(),355						"rename attribute may only be specified once",356					));357				}358				out.rename = Some(name.value());359			} else if lookahead.peek(kw::flatten) {360				input.parse::<kw::flatten>()?;361				out.flatten = true;362			} else if input.is_empty() {363				break;364			} else {365				return Err(lookahead.error());366			}367			if input.peek(Token![,]) {368				input.parse::<Token![,]>()?;369			} else {370				break;371			}372		}373		// input.parse::<kw::rename>()?;374		// input.parse::<Token![=]>()?;375		// let rename = input.parse::<LitStr>()?.value();376		Ok(out)377	}378}379380struct TypedField<'f>(&'f syn::Field, TypedAttr);381impl<'f> TypedField<'f> {382	fn try_new(field: &'f syn::Field) -> Result<Self> {383		let attr =384			parse_attr::<TypedAttr, _>(&field.attrs, "typed")?.unwrap_or_else(Default::default);385		if field.ident.is_none() {386			return Err(Error::new(387				field.span(),388				"this field should appear in output object, but it has no visible name",389			));390		}391		Ok(Self(field, attr))392	}393	fn ident(&self) -> Ident {394		self.0395			.ident396			.clone()397			.expect("constructor disallows fields without name")398	}399	/// None if this field is flattened in jsonnet output400	fn name(&self) -> Option<String> {401		if self.1.flatten {402			return None;403		}404		Some(405			self.1406				.rename407				.clone()408				.unwrap_or_else(|| self.ident().to_string()),409		)410	}411412	fn expand_field(&self) -> Option<TokenStream> {413		if self.is_option() {414			return None;415		}416		let name = self.name()?;417		let ty = &self.0.ty;418		Some(quote! {419			(#name, <#ty>::TYPE)420		})421	}422	fn expand_parse(&self) -> TokenStream {423		let ident = self.ident();424		let ty = &self.0.ty;425		if self.1.flatten {426			// optional flatten is handled in same way as serde427			return if self.is_option() {428				quote! {429					#ident: <#ty>::parse(&obj).ok(),430				}431			} else {432				quote! {433					#ident: <#ty>::parse(&obj)?,434				}435			};436		};437438		let name = self.name().unwrap();439		let value = if let Some(ty) = self.as_option() {440			quote! {441				if let Some(value) = obj.get(#name.into())? {442					Some(<#ty>::try_from(vakue)?)443				} else {444					None445				}446			}447		} else {448			quote! {449				<#ty>::try_from(obj.get(#name.into())?.ok_or_else(|| Error::NoSuchField(#name.into()))?)?450			}451		};452453		quote! {454			#ident: #value,455		}456	}457	fn expand_serialize(&self) -> TokenStream {458		let ident = self.ident();459		if let Some(name) = self.name() {460			if self.is_option() {461				quote! {462					if let Some(value) = self.#ident {463						out.member(#name.into()).value(value.try_into()?);464					}465				}466			} else {467				quote! {468					out.member(#name.into()).value(self.#ident.try_into()?);469				}470			}471		} else {472			if self.is_option() {473				quote! {474					if let Some(value) = self.#ident {475						value.serialize(out)?;476					}477				}478			} else {479				quote! {480					self.#ident.serialize(out)?;481				}482			}483		}484	}485486	fn as_option(&self) -> Option<&Type> {487		extract_type_from_option(&self.0.ty).unwrap()488	}489	fn is_option(&self) -> bool {490		self.as_option().is_some()491	}492}493494#[proc_macro_derive(Typed, attributes(typed))]495pub fn derive_typed(item: proc_macro::TokenStream) -> proc_macro::TokenStream {496	let input = parse_macro_input!(item as DeriveInput);497498	match derive_typed_inner(input) {499		Ok(v) => v.into(),500		Err(e) => e.to_compile_error().into(),501	}502}503504fn derive_typed_inner(input: DeriveInput) -> Result<TokenStream> {505	let data = match &input.data {506		syn::Data::Struct(s) => s,507		_ => return Err(Error::new(input.span(), "only structs supported")),508	};509510	let ident = &input.ident;511	let fields = data512		.fields513		.iter()514		.map(TypedField::try_new)515		.collect::<Result<Vec<_>>>()?;516517	let typed = {518		let fields = fields519			.iter()520			.flat_map(TypedField::expand_field)521			.collect::<Vec<_>>();522		let len = fields.len();523		quote! {524			const ITEMS: [(&'static str, &'static ComplexValType); #len] = [525				#(#fields,)*526			];527			impl Typed for #ident {528				const TYPE: &'static ComplexValType = &ComplexValType::ObjectRef(&ITEMS);529			}530		}531	};532533	let fields_parse = fields.iter().map(TypedField::expand_parse);534	let fields_serialize = fields.iter().map(TypedField::expand_serialize);535536	Ok(quote! {537		const _: () = {538			use ::jrsonnet_evaluator::{539				typed::{ComplexValType, Typed, TypedObj, CheckType},540				Val,541				error::{LocError, Error},542				ObjValueBuilder, ObjValue,543			};544545			#typed546547			impl #ident {548				fn serialize(self, out: &mut ObjValueBuilder) -> Result<(), LocError> {549					#(#fields_serialize)*550551					Ok(())552				}553				fn parse(obj: &ObjValue) -> Result<Self, LocError> {554					Ok(Self {555						#(#fields_parse)*556					})557				}558			}559560			impl TryFrom<Val> for #ident {561				type Error = LocError;562				fn try_from(value: Val) -> Result<Self, Self::Error> {563					let obj = value.as_obj().expect("shape is correct");564					Self::parse(&obj)565				}566			}567			impl TryInto<Val> for #ident {568				type Error = LocError;569				fn try_into(self) -> Result<Val, Self::Error> {570					let mut out = ObjValueBuilder::new();571					self.serialize(&mut out)?;572					Ok(Val::Obj(out.build()))573				}574			}575			()576		};577	})578}