From bd50dd196053898aeb2e1288bf9226973c34b75b Mon Sep 17 00:00:00 2001 From: Yaroslav Bolyukin Date: Sun, 22 Mar 2026 02:36:46 +0000 Subject: [PATCH] refactor: split Typed into FromUntyped and IntoUntyped --- --- a/bindings/jsonnet/src/native.rs +++ b/bindings/jsonnet/src/native.rs @@ -6,7 +6,7 @@ use jrsonnet_evaluator::{ error::{Error, ErrorKind}, function::builtin::{NativeCallback, NativeCallbackHandler}, - typed::Typed, + typed::FromUntyped as _, IStr, Val, }; --- a/cmds/jrsonnet/Cargo.toml +++ b/cmds/jrsonnet/Cargo.toml @@ -11,10 +11,6 @@ workspace = true [features] -default = [ - "exp-regex", -] - experimental = [ "exp-preserve-order", "exp-destruct", --- a/crates/jrsonnet-evaluator/src/arr/mod.rs +++ b/crates/jrsonnet-evaluator/src/arr/mod.rs @@ -5,11 +5,11 @@ rc::Rc, }; -use jrsonnet_gcmodule::{cc_dyn, Cc, Trace}; +use jrsonnet_gcmodule::{cc_dyn, Cc}; use jrsonnet_interner::IBytes; use jrsonnet_parser::{Expr, Spanned}; -use crate::{function::NativeFn, typed::Typed, Context, Result, Thunk, Val}; +use crate::{function::NativeFn, Context, Result, Thunk, Val}; mod spec; pub use spec::{ArrayLike, *}; @@ -241,4 +241,3 @@ self.0.is_cheap() } } - --- a/crates/jrsonnet-evaluator/src/arr/spec.rs +++ b/crates/jrsonnet-evaluator/src/arr/spec.rs @@ -8,8 +8,11 @@ use super::ArrValue; use crate::function::NativeFn; use crate::{ - error::ErrorKind::InfiniteRecursionDetected, evaluate, typed::Typed, val::ThunkValue, Context, - Error, ObjValue, Result, Thunk, Val, + error::ErrorKind::InfiniteRecursionDetected, + evaluate, + typed::{IntoUntyped, Typed}, + val::ThunkValue, + Context, Error, ObjValue, Result, Thunk, Val, }; pub trait ArrayLike: Any + Trace + Debug { --- a/crates/jrsonnet-evaluator/src/evaluate/mod.rs +++ b/crates/jrsonnet-evaluator/src/evaluate/mod.rs @@ -20,7 +20,7 @@ function::{CallLocation, FuncDesc, FuncVal}, gc::WithCapacityExt as _, in_frame, - typed::Typed, + typed::{FromUntyped, IntoUntyped as _, Typed}, val::{CachedUnbound, IndexableVal, NumValue, StrValue, Thunk}, with_state, Context, Error, ObjValue, ObjValueBuilder, ObjectAssertion, Pending, Result, ResultExt, SupThis, Unbound, Val, @@ -620,7 +620,7 @@ } } Slice(slice) => { - fn parse_idx( + fn parse_idx( loc: CallLocation<'_>, ctx: Context, expr: Option<&Spanned>, --- a/crates/jrsonnet-evaluator/src/evaluate/operator.rs +++ b/crates/jrsonnet-evaluator/src/evaluate/operator.rs @@ -8,7 +8,7 @@ error::ErrorKind::*, evaluate, stdlib::std_format, - typed::Typed, + typed::IntoUntyped as _, val::{equals, StrValue}, Context, Result, Val, }; --- a/crates/jrsonnet-evaluator/src/function/native.rs +++ b/crates/jrsonnet-evaluator/src/function/native.rs @@ -3,7 +3,11 @@ use jrsonnet_gcmodule::Trace; use super::PreparedFuncVal; -use crate::{bail, function::FuncVal, typed::Typed, CallLocation, Result, Val}; +use crate::{ + function::FuncVal, + typed::{FromUntyped, IntoUntyped, Typed}, + CallLocation, Result, Val, +}; use jrsonnet_types::{ComplexValType, ValType}; #[derive(Debug, Trace, Clone)] @@ -12,8 +16,8 @@ ($i:expr; $($gen:ident)*) => { impl<$($gen,)* O> NativeFn<($($gen,)* O,)> where - $($gen: Typed,)* - O: Typed, + $($gen: Typed + IntoUntyped,)* + O: Typed + FromUntyped, { #[allow(non_snake_case, clippy::too_many_arguments)] pub fn call( @@ -22,7 +26,7 @@ ) -> Result { let val = self.0.call( CallLocation::native(), - &[$(Typed::into_lazy_untyped($gen),)*], + &[$(IntoUntyped::into_lazy_untyped($gen),)*], &[], )?; O::from_untyped(val) @@ -30,11 +34,9 @@ } impl<$($gen,)* O> Typed for NativeFn<($($gen,)* O,)> { const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Func); - - fn into_untyped(_typed: Self) -> Result { - bail!("can only convert functions from jsonnet to native") - } + } + impl<$($gen,)* O> FromUntyped for NativeFn<($($gen,)* O,)> { fn from_untyped(untyped: Val) -> Result { let func = FuncVal::from_untyped(untyped)?; Ok(Self( --- a/crates/jrsonnet-evaluator/src/stdlib/format.rs +++ b/crates/jrsonnet-evaluator/src/stdlib/format.rs @@ -9,7 +9,7 @@ use crate::{ bail, error::{format_found, suggest_object_fields, ErrorKind::*}, - typed::Typed, + typed::FromUntyped, Error, ObjValue, Result, Val, }; --- a/crates/jrsonnet-evaluator/src/typed/conversions.rs +++ b/crates/jrsonnet-evaluator/src/typed/conversions.rs @@ -1,6 +1,6 @@ use std::{collections::BTreeMap, marker::PhantomData, ops::Deref}; -use jrsonnet_gcmodule::{Cc, Trace}; +use jrsonnet_gcmodule::Trace; use jrsonnet_interner::{IBytes, IStr}; pub use jrsonnet_macros::Typed; use jrsonnet_types::{ComplexValType, ValType}; @@ -8,17 +8,17 @@ use crate::{ arr::{ArrValue, BytesArray}, bail, - function::{FuncDesc, FuncVal}, + function::FuncVal, typed::CheckType, val::{IndexableVal, NumValue, StrValue, ThunkMapper}, ObjValue, ObjValueBuilder, Result, ResultExt, Thunk, Val, }; #[derive(Trace)] -struct FromUntyped(PhantomData K>); -impl ThunkMapper for FromUntyped +struct ThunkFromUntyped(PhantomData K>); +impl ThunkMapper for ThunkFromUntyped where - K: Typed + Trace, + K: Typed + FromUntyped + Trace, { type Output = K; @@ -26,12 +26,29 @@ K::from_untyped(from) } } -impl Default for FromUntyped { +impl Default for ThunkFromUntyped { fn default() -> Self { Self(PhantomData) } } +#[derive(Trace)] +struct ThunkIntoUntyped(PhantomData K>); +impl ThunkMapper for ThunkIntoUntyped +where + K: Typed + Trace + IntoUntyped, +{ + type Output = Val; + fn map(self, from: K) -> Result { + K::into_untyped(from) + } +} +impl Default for ThunkIntoUntyped { + fn default() -> Self { + Self(PhantomData) + } +} + pub trait TypedObj: Typed { fn serialize(self, out: &mut ObjValueBuilder) -> Result<()>; fn parse(obj: &ObjValue) -> Result; @@ -44,31 +61,41 @@ pub trait Typed: Sized { const TYPE: &'static ComplexValType; +} +pub trait IntoUntyped: Typed { + // Whatever caller should use `into_lazy_untyped` instead of `into_untyped` + fn provides_lazy() -> bool { + false + } fn into_untyped(typed: Self) -> Result; fn into_lazy_untyped(typed: Self) -> Thunk { Thunk::from(Self::into_untyped(typed)) } +} +pub trait IntoUntypedResult: Typed { + /// Hack to make builtins be able to return non-result values, and make macros able to convert those values to result + /// This method returns identity in impl Typed for Result, and should not be overriden + #[doc(hidden)] + fn into_untyped_result(typed: Self) -> Result; +} +impl IntoUntypedResult for T +where + T: IntoUntyped, +{ + fn into_untyped_result(typed: Self) -> Result { + T::into_untyped(typed) + } +} + +pub trait FromUntyped: Typed { fn from_untyped(untyped: Val) -> Result; fn from_lazy_untyped(lazy: Thunk) -> Result { Self::from_untyped(lazy.evaluate()?) } - // Whatever caller should use `into_lazy_untyped` instead of `into_untyped` - fn provides_lazy() -> bool { - false - } - // Whatever caller should use `from_lazy_untyped` instead of `from_untyped` when possible fn wants_lazy() -> bool { false - } - - /// Hack to make builtins be able to return non-result values, and make macros able to convert those values to result - /// This method returns identity in impl Typed for Result, and should not be overriden - #[doc(hidden)] - fn into_result(typed: Self) -> Result { - let value = Self::into_untyped(typed)?; - Ok(value) } } @@ -77,38 +104,30 @@ T: Typed + Trace + Clone, { const TYPE: &'static ComplexValType = &ComplexValType::Lazy(T::TYPE); +} +impl IntoUntyped for Thunk +where + T: Typed + IntoUntyped + Trace + Clone, +{ fn into_untyped(typed: Self) -> Result { T::into_untyped(typed.evaluate()?) - } - - fn from_untyped(untyped: Val) -> Result { - Self::from_lazy_untyped(Thunk::evaluated(untyped)) } - fn provides_lazy() -> bool { true } fn into_lazy_untyped(inner: Self) -> Thunk { - #[derive(Trace)] - struct IntoUntyped(PhantomData K>); - impl ThunkMapper for IntoUntyped - where - K: Typed + Trace, - { - type Output = Val; + inner.map(>::default()) + } +} - fn map(self, from: K) -> Result { - K::into_untyped(from) - } - } - impl Default for IntoUntyped { - fn default() -> Self { - Self(PhantomData) - } - } - inner.map(>::default()) +impl FromUntyped for Thunk +where + T: Typed + FromUntyped + Trace + Clone, +{ + fn from_untyped(untyped: Val) -> Result { + Self::from_lazy_untyped(Thunk::evaluated(untyped)) } fn wants_lazy() -> bool { @@ -116,7 +135,7 @@ } fn from_lazy_untyped(inner: Thunk) -> Result { - Ok(inner.map(>::default())) + Ok(inner.map(>::default())) } } @@ -128,6 +147,8 @@ impl Typed for $ty { const TYPE: &'static ComplexValType = &ComplexValType::BoundedNumber(Some(Self::MIN as f64), Some(Self::MAX as f64)); + } + impl FromUntyped for $ty { fn from_untyped(value: Val) -> Result { ::TYPE.check(&value)?; match value { @@ -145,6 +166,8 @@ _ => unreachable!(), } } + } + impl IntoUntyped for $ty { fn into_untyped(value: Self) -> Result { Ok(Val::Num(value.into())) } @@ -183,7 +206,9 @@ Some(MIN as f64), Some(MAX as f64), ); + } + impl FromUntyped for $name { fn from_untyped(value: Val) -> Result { ::TYPE.check(&value)?; match value { @@ -201,7 +226,9 @@ _ => unreachable!(), } } + } + impl IntoUntyped for $name { #[allow(clippy::cast_lossless)] fn into_untyped(value: Self) -> Result { Ok(Val::try_num(value.0)?) @@ -220,11 +247,13 @@ impl Typed for f64 { const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Num); - +} +impl IntoUntyped for f64 { fn into_untyped(value: Self) -> Result { Ok(Val::try_num(value)?) } - +} +impl FromUntyped for f64 { fn from_untyped(value: Val) -> Result { ::TYPE.check(&value)?; match value { @@ -237,11 +266,13 @@ pub struct PositiveF64(pub f64); impl Typed for PositiveF64 { const TYPE: &'static ComplexValType = &ComplexValType::BoundedNumber(Some(0.0), None); - +} +impl IntoUntyped for PositiveF64 { fn into_untyped(value: Self) -> Result { Ok(Val::try_num(value.0)?) } - +} +impl FromUntyped for PositiveF64 { fn from_untyped(value: Val) -> Result { ::TYPE.check(&value)?; match value { @@ -253,11 +284,13 @@ impl Typed for usize { const TYPE: &'static ComplexValType = &ComplexValType::BoundedNumber(Some(0.0), Some(MAX_SAFE_INTEGER)); - +} +impl IntoUntyped for usize { fn into_untyped(value: Self) -> Result { Ok(Val::try_num(value)?) } - +} +impl FromUntyped for usize { fn from_untyped(value: Val) -> Result { ::TYPE.check(&value)?; match value { @@ -276,11 +309,13 @@ impl Typed for IStr { const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Str); - +} +impl IntoUntyped for IStr { fn into_untyped(value: Self) -> Result { Ok(Val::string(value)) } - +} +impl FromUntyped for IStr { fn from_untyped(value: Val) -> Result { ::TYPE.check(&value)?; match value { @@ -292,11 +327,13 @@ impl Typed for String { const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Str); - +} +impl IntoUntyped for String { fn into_untyped(value: Self) -> Result { Ok(Val::string(value)) } - +} +impl FromUntyped for String { fn from_untyped(value: Val) -> Result { ::TYPE.check(&value)?; match value { @@ -308,11 +345,13 @@ impl Typed for StrValue { const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Str); - +} +impl IntoUntyped for StrValue { fn into_untyped(value: Self) -> Result { Ok(Val::Str(value)) } - +} +impl FromUntyped for StrValue { fn from_untyped(value: Val) -> Result { ::TYPE.check(&value)?; match value { @@ -324,11 +363,13 @@ impl Typed for char { const TYPE: &'static ComplexValType = &ComplexValType::Char; - +} +impl IntoUntyped for char { fn into_untyped(value: Self) -> Result { Ok(Val::string(value)) } - +} +impl FromUntyped for char { fn from_untyped(value: Val) -> Result { ::TYPE.check(&value)?; match value { @@ -338,12 +379,14 @@ } } +// TODO: View into vec using ArrayLike? impl Typed for Vec where T: Typed, { const TYPE: &'static ComplexValType = &ComplexValType::ArrayRef(T::TYPE); - +} +impl IntoUntyped for Vec { fn into_untyped(value: Self) -> Result { Ok(Val::Arr( value @@ -352,7 +395,8 @@ .collect::>()?, )) } - +} +impl FromUntyped for Vec { fn from_untyped(value: Val) -> Result { let Val::Arr(a) = value else { ::TYPE.check(&value)?; @@ -369,9 +413,19 @@ } } -impl Typed for BTreeMap { +// TODO: View into BTreeMap using ObjectCore? +impl Typed for BTreeMap +where + K: Typed + Ord, + V: Typed, +{ const TYPE: &'static ComplexValType = &ComplexValType::AttrsOf(V::TYPE); - +} +impl IntoUntyped for BTreeMap +where + K: Typed + Ord + IntoUntyped, + V: Typed + IntoUntyped, +{ fn into_untyped(typed: Self) -> Result { let mut out = ObjValueBuilder::with_capacity(typed.len()); for (k, v) in typed { @@ -383,7 +437,12 @@ } Ok(Val::Obj(out.build())) } - +} +impl FromUntyped for BTreeMap +where + K: FromUntyped + Ord, + V: FromUntyped, +{ fn from_untyped(value: Val) -> Result { Self::TYPE.check(&value)?; let obj = value.as_obj().expect("typecheck should fail"); @@ -416,32 +475,27 @@ impl Typed for Val { const TYPE: &'static ComplexValType = &ComplexValType::Any; - +} +impl IntoUntyped for Val { fn into_untyped(typed: Self) -> Result { Ok(typed) } +} +impl FromUntyped for Val { fn from_untyped(untyped: Val) -> Result { Ok(untyped) } } -// Hack #[doc(hidden)] impl Typed for Result where T: Typed, { const TYPE: &'static ComplexValType = &ComplexValType::Any; - - fn into_untyped(_typed: Self) -> Result { - panic!("do not use this conversion") - } - - fn from_untyped(_untyped: Val) -> Result { - panic!("do not use this conversion") - } - - fn into_result(typed: Self) -> Result { +} +impl IntoUntypedResult for Result { + fn into_untyped_result(typed: Self) -> Result { typed.map(T::into_untyped)? } } @@ -450,11 +504,13 @@ impl Typed for IBytes { const TYPE: &'static ComplexValType = &ComplexValType::ArrayRef(&ComplexValType::BoundedNumber(Some(0.0), Some(255.0))); - +} +impl IntoUntyped for IBytes { fn into_untyped(value: Self) -> Result { Ok(Val::Arr(ArrValue::bytes(value))) } - +} +impl FromUntyped for IBytes { fn from_untyped(value: Val) -> Result { let Val::Arr(a) = &value else { ::TYPE.check(&value)?; @@ -477,11 +533,13 @@ pub struct M1; impl Typed for M1 { const TYPE: &'static ComplexValType = &ComplexValType::BoundedNumber(Some(-1.0), Some(-1.0)); - +} +impl IntoUntyped for M1 { fn into_untyped(_: Self) -> Result { Ok(Val::Num(NumValue::new(-1.0).expect("finite"))) } - +} +impl FromUntyped for M1 { fn from_untyped(value: Val) -> Result { ::TYPE.check(&value)?; Ok(Self) @@ -499,13 +557,22 @@ $($id: Typed,)* { const TYPE: &'static ComplexValType = &ComplexValType::UnionRef(&[$($id::TYPE),*]); - + } + impl<$($id),*> IntoUntyped for $name<$($id),*> + where + $($id: Typed + IntoUntyped,)* + { fn into_untyped(value: Self) -> Result { match value {$( $name::$id(v) => $id::into_untyped(v) ),*} } + } + impl<$($id),*> FromUntyped for $name<$($id),*> + where + $($id: Typed + FromUntyped,)* + { fn from_untyped(value: Val) -> Result { $( if $id::TYPE.check(&value).is_ok() { @@ -544,11 +611,13 @@ impl Typed for ArrValue { const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Arr); - +} +impl IntoUntyped for ArrValue { fn into_untyped(value: Self) -> Result { Ok(Val::Arr(value)) } - +} +impl FromUntyped for ArrValue { fn from_untyped(value: Val) -> Result { ::TYPE.check(&value)?; match value { @@ -560,32 +629,17 @@ impl Typed for FuncVal { const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Func); - +} +impl IntoUntyped for FuncVal { fn into_untyped(value: Self) -> Result { Ok(Val::Func(value)) } - - fn from_untyped(value: Val) -> Result { - ::TYPE.check(&value)?; - match value { - Val::Func(a) => Ok(a), - _ => unreachable!(), - } - } } - -impl Typed for Cc { - const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Func); - - fn into_untyped(value: Self) -> Result { - Ok(Val::Func(FuncVal::Normal(value))) - } - +impl FromUntyped for FuncVal { fn from_untyped(value: Val) -> Result { ::TYPE.check(&value)?; match value { - Val::Func(FuncVal::Normal(desc)) => Ok(desc), - Val::Func(_) => bail!("expected normal function, not builtin"), + Val::Func(a) => Ok(a), _ => unreachable!(), } } @@ -593,11 +647,13 @@ impl Typed for ObjValue { const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Obj); - +} +impl IntoUntyped for ObjValue { fn into_untyped(value: Self) -> Result { Ok(Val::Obj(value)) } - +} +impl FromUntyped for ObjValue { fn from_untyped(value: Val) -> Result { ::TYPE.check(&value)?; match value { @@ -609,11 +665,13 @@ impl Typed for bool { const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Bool); - +} +impl IntoUntyped for bool { fn into_untyped(value: Self) -> Result { Ok(Val::Bool(value)) } - +} +impl FromUntyped for bool { fn from_untyped(value: Val) -> Result { ::TYPE.check(&value)?; match value { @@ -622,19 +680,22 @@ } } } + impl Typed for IndexableVal { const TYPE: &'static ComplexValType = &ComplexValType::UnionRef(&[ &ComplexValType::Simple(ValType::Arr), &ComplexValType::Simple(ValType::Str), ]); - +} +impl IntoUntyped for IndexableVal { fn into_untyped(value: Self) -> Result { match value { Self::Str(s) => Ok(Val::string(s)), Self::Arr(a) => Ok(Val::Arr(a)), } } - +} +impl FromUntyped for IndexableVal { fn from_untyped(value: Val) -> Result { ::TYPE.check(&value)?; value.into_indexable() @@ -644,11 +705,13 @@ pub struct Null; impl Typed for Null { const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Null); - +} +impl IntoUntyped for Null { fn into_untyped(_: Self) -> Result { Ok(Val::Null) } - +} +impl FromUntyped for Null { fn from_untyped(value: Val) -> Result { ::TYPE.check(&value)?; Ok(Self) @@ -661,11 +724,19 @@ { const TYPE: &'static ComplexValType = &ComplexValType::UnionRef(&[&ComplexValType::Simple(ValType::Null), T::TYPE]); - +} +impl IntoUntyped for Option +where + T: Typed + IntoUntyped, +{ fn into_untyped(typed: Self) -> Result { typed.map_or_else(|| Ok(Val::Null), |v| T::into_untyped(v)) } - +} +impl FromUntyped for Option +where + T: Typed + FromUntyped, +{ fn from_untyped(untyped: Val) -> Result { if matches!(untyped, Val::Null) { Ok(None) @@ -677,11 +748,13 @@ impl Typed for NumValue { const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Num); - +} +impl IntoUntyped for NumValue { fn into_untyped(typed: Self) -> Result { Ok(Val::Num(typed)) } - +} +impl FromUntyped for NumValue { fn from_untyped(untyped: Val) -> Result { Self::TYPE.check(&untyped)?; match untyped { --- a/crates/jrsonnet-interner/src/names.rs +++ b/crates/jrsonnet-interner/src/names.rs @@ -0,0 +1 @@ + --- a/crates/jrsonnet-macros/src/lib.rs +++ b/crates/jrsonnet-macros/src/lib.rs @@ -8,15 +8,15 @@ parse_macro_input, punctuated::Punctuated, spanned::Spanned, - token::{self, Comma}, + token::Comma, Attribute, DeriveInput, Error, Expr, ExprClosure, FnArg, GenericArgument, Ident, ItemFn, LitStr, Meta, Pat, Path, PathArguments, Result, ReturnType, Token, Type, }; use self::typed::derive_typed_inner; +mod names; mod typed; -mod names; fn try_parse_attr_noargs(attrs: &[Attribute], ident: I) -> Result where @@ -202,7 +202,7 @@ _ => {} } - let (optionality, ty) = if try_parse_attr_noargs(&mut arg.attrs, "default")? { + let (optionality, ty) = if try_parse_attr_noargs(&arg.attrs, "default")? { remove_attr(&mut arg.attrs, "default"); (Optionality::TypeDefault, ty.clone()) } else if let Some(default) = parse_attr::<_, _>(&arg.attrs, "default")? { @@ -322,7 +322,7 @@ let name = name.as_ref().map_or("", String::as_str); let eval = quote! {jrsonnet_evaluator::in_description_frame( || format!("argument <{}> evaluation", #name), - || <#ty>::from_untyped(value.evaluate()?), + || <#ty as FromUntyped>::from_untyped(value.evaluate()?), )?}; let value = match optionality { Optionality::Required => quote! {{ @@ -411,7 +411,7 @@ use ::jrsonnet_evaluator::{ State, Val, function::{builtin::{Builtin, StaticBuiltin}, FunctionSignature, ParamParse, ParamName, ParamDefault, CallLocation}, - Result, Context, typed::Typed, + Result, Context, typed::{Typed, FromUntyped, IntoUntypedResult}, parser::Span, params, Thunk, }; params!( @@ -432,7 +432,7 @@ #[allow(unused_variables)] fn call(&self, location: CallLocation<'_>, parsed: &[Option>]) -> Result { let result: #result = #name(#(#pass)*); - <_ as Typed>::into_result(result) + <_ as IntoUntypedResult>::into_untyped_result(result) } fn as_any(&self) -> &dyn ::std::any::Any { self --- a/crates/jrsonnet-macros/src/names.rs +++ b/crates/jrsonnet-macros/src/names.rs @@ -1,6 +1,5 @@ use proc_macro2::TokenStream; use quote::quote; -use std::cell::RefCell; #[derive(Default)] pub struct Names { --- a/crates/jrsonnet-macros/src/typed.rs +++ b/crates/jrsonnet-macros/src/typed.rs @@ -178,7 +178,7 @@ None }; - __value.map(<#ty as Typed>::from_untyped).transpose()? + __value.map(<#ty as FromUntyped>::from_untyped).transpose()? }, } } @@ -219,7 +219,7 @@ return Err(ErrorKind::NoSuchField(__names[#error_text].clone(), vec![]).into()); }; - <#ty as Typed>::from_untyped(__value)? + <#ty as FromUntyped>::from_untyped(__value)? }, } } @@ -258,14 +258,14 @@ out.field(__names[#name].clone()) #hide #add - .try_thunk(<#ty as Typed>::into_lazy_untyped(value))?; + .try_thunk(<#ty as IntoUntyped>::into_lazy_untyped(value))?; } } else { quote! { out.field(__names[#name].clone()) #hide #add - .try_value(<#ty as Typed>::into_untyped(value)?)?; + .try_value(<#ty as IntoUntyped>::into_untyped(value)?)?; } }; if self.is_option { @@ -313,18 +313,21 @@ const TYPE: &'static ComplexValType = &ComplexValType::ObjectRef(&[ #(#fields,)* ]); + } + impl #impl_generics FromUntyped for #ident #ty_generics #where_clause { fn from_untyped(value: Val) -> JrResult { let obj = value.as_obj().expect("shape is correct"); Self::parse(&obj) } + } + impl #impl_generics IntoUntyped for #ident #ty_generics #where_clause { fn into_untyped(value: Self) -> JrResult { let mut out = ObjValueBuilder::with_capacity(#capacity); value.serialize(&mut out)?; Ok(Val::Obj(out.build())) } - } } }; @@ -344,7 +347,7 @@ Ok(quote! { const _: () = { use ::jrsonnet_evaluator::{ - typed::{ComplexValType, Typed, TypedObj, CheckType}, + typed::{ComplexValType, Typed, IntoUntyped, FromUntyped, TypedObj, CheckType}, Val, State, error::{ErrorKind, Result as JrResult}, ObjValueBuilder, ObjValue, IStr, --- a/crates/jrsonnet-stdlib/src/arrays.rs +++ b/crates/jrsonnet-stdlib/src/arrays.rs @@ -4,7 +4,7 @@ bail, function::{builtin, FuncVal, NativeFn}, runtime_error, - typed::{BoundedI32, BoundedUsize, Either2, Typed}, + typed::{BoundedI32, BoundedUsize, Either2, FromUntyped}, val::{equals, ArrValue, IndexableVal}, Either, IStr, ObjValue, ObjValueBuilder, Result, ResultExt, Thunk, Val, }; @@ -24,7 +24,7 @@ } func.evaluate_trivial().map_or_else( // TODO: Different mapped array impl avoiding allocating unnecessary vals - || Ok(ArrValue::range_exclusive(0, *sz).map(Typed::from_untyped(Val::Func(func))?)), + || Ok(ArrValue::range_exclusive(0, *sz).map(FromUntyped::from_untyped(Val::Func(func))?)), |trivial| { let mut out = Vec::with_capacity(*sz as usize); for _ in 0..*sz { --- a/crates/jrsonnet-stdlib/src/keyf.rs +++ b/crates/jrsonnet-stdlib/src/keyf.rs @@ -1,5 +1,5 @@ use jrsonnet_evaluator::function::{CallLocation, FuncVal, PreparedFuncVal}; -use jrsonnet_evaluator::typed::{ComplexValType, Typed, ValType}; +use jrsonnet_evaluator::typed::{ComplexValType, FromUntyped, Typed, ValType}; use jrsonnet_evaluator::{Error, Result, Thunk, Val}; #[derive(Default, Clone)] @@ -31,11 +31,9 @@ impl Typed for KeyF { const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Func); +} +impl FromUntyped for KeyF { fn from_untyped(untyped: Val) -> Result { FuncVal::from_untyped(untyped).map(Self::new) - } - - fn into_untyped(_typed: Self) -> Result { - unreachable!("unused, todo: port split of Typed trait from #193") } } --- a/crates/jrsonnet-stdlib/src/manifest/ini.rs +++ b/crates/jrsonnet-stdlib/src/manifest/ini.rs @@ -2,7 +2,7 @@ use jrsonnet_evaluator::{ manifest::{ManifestFormat, ToStringFormat}, - typed::Typed, + typed::{FromUntyped, Typed}, ObjValue, Result, ResultExt, Val, }; use jrsonnet_parser::IStr; --- a/crates/jrsonnet-stdlib/src/manifest/xml.rs +++ b/crates/jrsonnet-stdlib/src/manifest/xml.rs @@ -1,7 +1,7 @@ use jrsonnet_evaluator::{ bail, in_description_frame, manifest::{ManifestFormat, ToStringFormat}, - typed::{ComplexValType, Either2, Typed, ValType}, + typed::{ComplexValType, Either2, FromUntyped, Typed, ValType}, val::ArrValue, Either, ObjValue, Result, ResultExt, Val, }; @@ -32,11 +32,8 @@ } impl Typed for JSONMLValue { const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Arr); - - fn into_untyped(_typed: Self) -> Result { - unreachable!("not used, reserved for parseXML?") - } - +} +impl FromUntyped for JSONMLValue { fn from_untyped(untyped: Val) -> Result { let val = ::from_untyped(untyped) .description("parsing JSONML value (an array or string)")?; @@ -73,7 +70,7 @@ children: in_description_frame( || "parsing children".to_owned(), || { - Typed::from_untyped(Val::Arr(arr.slice( + FromUntyped::from_untyped(Val::Arr(arr.slice( Some(if has_attrs { 2 } else { 1 }), None, None, --- a/crates/jrsonnet-stdlib/src/strings.rs +++ b/crates/jrsonnet-stdlib/src/strings.rs @@ -4,7 +4,7 @@ bail, error::{ErrorKind::*, Result}, function::builtin, - typed::{Either2, Typed, M1}, + typed::{Either2, FromUntyped, M1}, val::{ArrValue, IndexableVal}, Either, IStr, Val, }; --- a/tests/tests/builtin.rs +++ b/tests/tests/builtin.rs @@ -5,7 +5,7 @@ function::{CallLocation, FuncVal, builtin, builtin::Builtin}, parser::Source, trace::PathResolver, - typed::Typed, + typed::FromUntyped, }; use jrsonnet_gcmodule::Trace; use jrsonnet_stdlib::ContextInitializer as StdContextInitializer; --- a/tests/tests/typed_obj.rs +++ b/tests/tests/typed_obj.rs @@ -2,7 +2,11 @@ use std::fmt::Debug; -use jrsonnet_evaluator::{Result, State, trace::PathResolver, typed::Typed}; +use jrsonnet_evaluator::{ + Result, State, + trace::PathResolver, + typed::{FromUntyped, IntoUntyped, Typed}, +}; use jrsonnet_stdlib::ContextInitializer; #[derive(Clone, Typed, PartialEq, Debug)] @@ -11,7 +15,9 @@ b: u16, } -fn test_roundtrip(value: T) -> Result<()> { +fn test_roundtrip( + value: T, +) -> Result<()> { let untyped = T::into_untyped(value.clone())?; let value2 = T::from_untyped(untyped.clone())?; ensure_eq!(value, value2); -- gitstuff