difftreelog
refactor split Typed into FromUntyped and IntoUntyped
in: master
20 files changed
bindings/jsonnet/src/native.rsdiffbeforeafterboth--- 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,
};
cmds/jrsonnet/Cargo.tomldiffbeforeafterboth--- 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",
crates/jrsonnet-evaluator/src/arr/mod.rsdiffbeforeafterboth--- 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()
}
}
-
crates/jrsonnet-evaluator/src/arr/spec.rsdiffbeforeafterboth--- 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 {
crates/jrsonnet-evaluator/src/evaluate/mod.rsdiffbeforeafterboth--- 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<T: Typed>(
+ fn parse_idx<T: Typed + FromUntyped>(
loc: CallLocation<'_>,
ctx: Context,
expr: Option<&Spanned<Expr>>,
crates/jrsonnet-evaluator/src/evaluate/operator.rsdiffbeforeafterboth1use std::cmp::Ordering;23use jrsonnet_parser::{BinaryOpType, Expr, Spanned, UnaryOpType};45use crate::{6 arr::ArrValue,7 bail,8 error::ErrorKind::*,9 evaluate,10 stdlib::std_format,11 typed::Typed,12 val::{equals, StrValue},13 Context, Result, Val,14};1516pub fn evaluate_unary_op(op: UnaryOpType, b: &Val) -> Result<Val> {17 use UnaryOpType::*;18 use Val::*;19 Ok(match (op, b) {20 (Plus, Num(n)) => Val::Num(*n),21 (Minus, Num(n)) => Val::try_num(-n.get())?,22 (Not, Bool(v)) => Bool(!v),23 (BitNot, Num(n)) => Val::try_num(!(n.get() as i64) as f64)?,24 (op, o) => bail!(UnaryOperatorDoesNotOperateOnType(op, o.value_type())),25 })26}2728pub fn evaluate_add_op(a: &Val, b: &Val) -> Result<Val> {29 use Val::*;30 Ok(match (a, b) {31 (Str(v1), Str(v2)) => Str(StrValue::concat(v1.clone(), v2.clone())),3233 (Num(a), Str(b)) => Val::string(format!("{a}{b}")),34 (Str(a), Num(b)) => Val::string(format!("{a}{b}")),3536 (Str(a), o) | (o, Str(a)) if a.is_empty() => Val::string(o.clone().to_string()?),37 (Str(a), o) => Val::string(format!("{a}{}", o.clone().to_string()?)),38 (o, Str(a)) => Val::string(format!("{}{a}", o.clone().to_string()?)),3940 (Obj(v1), Obj(v2)) => Obj(v2.extend_from(v1.clone())),41 (Arr(a), Arr(b)) => Val::Arr(ArrValue::extended(a.clone(), b.clone())),4243 (Num(v1), Num(v2)) => Val::try_num(v1.get() + v2.get())?,4445 #[cfg(feature = "exp-bigint")]46 (BigInt(a), BigInt(b)) => BigInt(Box::new(&**a + &**b)),4748 _ => bail!(BinaryOperatorDoesNotOperateOnValues(49 BinaryOpType::Add,50 a.value_type(),51 b.value_type(),52 )),53 })54}5556pub fn evaluate_sub_op(a: &Val, b: &Val) -> Result<Val> {57 use Val::*;58 Ok(match (a, b) {59 (Num(v1), Num(v2)) => Val::try_num(v1.get() - v2.get())?,6061 #[cfg(feature = "exp-bigint")]62 (BigInt(a), BigInt(b)) => BigInt(Box::new(&**a - &**b)),6364 // TODO: Support objects and arrays65 _ => bail!(BinaryOperatorDoesNotOperateOnValues(66 BinaryOpType::Sub,67 a.value_type(),68 b.value_type(),69 )),70 })71}7273pub fn evaluate_mul_op(a: &Val, b: &Val) -> Result<Val> {74 use Val::*;75 Ok(match (a, b) {76 (Str(s), Num(c)) => Val::string(s.to_string().repeat(c.get() as usize)),77 (Num(c), Str(s)) => Val::string(s.to_string().repeat(c.get() as usize)),7879 (Num(v1), Num(v2)) => Val::try_num(v1.get() * v2.get())?,8081 #[cfg(feature = "exp-bigint")]82 (BigInt(a), BigInt(b)) => BigInt(Box::new(&**a * &**b)),8384 _ => bail!(BinaryOperatorDoesNotOperateOnValues(85 BinaryOpType::Mul,86 a.value_type(),87 b.value_type(),88 )),89 })90}9192fn is_attempt_to_divide_by_zero(a: &Val, b: &Val) -> bool {93 use Val::*;94 match (a, b) {95 // string format96 (Str(_), _) => false,9798 (_, Num(b)) => **b == 0.,99 #[cfg(feature = "exp-bigint")]100 (_, BigInt(b)) => **b == num_bigint::BigInt::ZERO,101102 // something else103 _ => false,104 }105}106107pub fn evaluate_div_op(a: &Val, b: &Val) -> Result<Val> {108 use Val::*;109110 if is_attempt_to_divide_by_zero(a, b) {111 bail!(DivisionByZero);112 }113114 Ok(match (a, b) {115 (Num(a), Num(b)) => Val::try_num(a.get() / b.get())?,116 #[cfg(feature = "exp-bigint")]117 (BigInt(a), BigInt(b)) => BigInt(Box::new(&**a / &**b)),118 (a, b) => bail!(BinaryOperatorDoesNotOperateOnValues(119 BinaryOpType::Div,120 a.value_type(),121 b.value_type()122 )),123 })124}125126pub fn evaluate_mod_op(a: &Val, b: &Val) -> Result<Val> {127 use Val::*;128129 if is_attempt_to_divide_by_zero(a, b) {130 bail!(DivisionByZero);131 }132133 Ok(match (a, b) {134 (Num(a), Num(b)) => Val::try_num(a.get() % b.get())?,135 #[cfg(feature = "exp-bigint")]136 (BigInt(a), BigInt(b)) => BigInt(Box::new(&**a % &**b)),137 (Str(str), vals) => {138 String::into_untyped(std_format(&str.clone().into_flat(), vals.clone())?)?139 }140 (a, b) => bail!(BinaryOperatorDoesNotOperateOnValues(141 BinaryOpType::Mod,142 a.value_type(),143 b.value_type()144 )),145 })146}147148pub fn evaluate_binary_op_special(149 ctx: Context,150 a: &Spanned<Expr>,151 op: BinaryOpType,152 b: &Spanned<Expr>,153) -> Result<Val> {154 use BinaryOpType::*;155 use Val::*;156 Ok(match (evaluate(ctx.clone(), a)?, op, b) {157 (Bool(true), Or, _o) => Val::Bool(true),158 (Bool(false), And, _o) => Val::Bool(false),159 #[cfg(feature = "exp-null-coaelse")]160 (Null, NullCoaelse, eb) => evaluate(ctx, eb)?,161 #[cfg(feature = "exp-null-coaelse")]162 (a, NullCoaelse, _o) => a,163 (a, op, eb) => evaluate_binary_op_normal(&a, op, &evaluate(ctx, eb)?)?,164 })165}166167pub fn evaluate_compare_op(a: &Val, b: &Val, op: BinaryOpType) -> Result<Ordering> {168 use Val::*;169 Ok(match (a, b) {170 (Str(a), Str(b)) => a.cmp(b),171172 (Num(a), Num(b)) => a.cmp(b),173174 #[cfg(feature = "exp-bigint")]175 (BigInt(a), BigInt(b)) => a.cmp(b),176177 (Arr(a), Arr(b)) => {178 let ai = a.iter();179 let bi = b.iter();180181 for (a, b) in ai.zip(bi) {182 let ord = evaluate_compare_op(&a?, &b?, op)?;183 if !ord.is_eq() {184 return Ok(ord);185 }186 }187 a.len().cmp(&b.len())188 }189 (_, _) => bail!(BinaryOperatorDoesNotOperateOnValues(190 op,191 a.value_type(),192 b.value_type()193 )),194 })195}196197pub fn evaluate_binary_op_normal(a: &Val, op: BinaryOpType, b: &Val) -> Result<Val> {198 use BinaryOpType::*;199 use Val::*;200 Ok(match (a, op, b) {201 (a, Eq, b) => Bool(equals(a, b)?),202 (a, Neq, b) => Bool(!equals(a, b)?),203204 (a, Lt, b) => Bool(evaluate_compare_op(a, b, Lt)?.is_lt()),205 (a, Gt, b) => Bool(evaluate_compare_op(a, b, Gt)?.is_gt()),206 (a, Lte, b) => Bool(evaluate_compare_op(a, b, Lte)?.is_le()),207 (a, Gte, b) => Bool(evaluate_compare_op(a, b, Gte)?.is_ge()),208209 (Str(a), In, Obj(obj)) => Bool(obj.has_field_ex(a.clone().into_flat(), true)),210211 // Bool X Bool212 (Bool(a), And, Bool(b)) => Bool(*a && *b),213 (Bool(a), Or, Bool(b)) => Bool(*a || *b),214215 (a, Add, b) => evaluate_add_op(a, b)?,216 (a, Sub, b) => evaluate_sub_op(a, b)?,217 (a, Mul, b) => evaluate_mul_op(a, b)?,218 (a, Div, b) => evaluate_div_op(a, b)?,219 (a, Mod, b) => evaluate_mod_op(a, b)?,220221 (Num(v1), BitAnd, Num(v2)) => {222 Val::try_num((v1.truncate_for_bitwise()? & v2.truncate_for_bitwise()?) as f64)?223 }224 (Num(v1), BitOr, Num(v2)) => {225 Val::try_num((v1.truncate_for_bitwise()? | v2.truncate_for_bitwise()?) as f64)?226 }227 (Num(v1), BitXor, Num(v2)) => {228 Val::try_num((v1.truncate_for_bitwise()? ^ v2.truncate_for_bitwise()?) as f64)?229 }230 (Num(v1), Lhs, Num(v2)) => {231 if v2.get() < 0.0 {232 bail!("shift by negative exponent")233 }234 let base = v1.truncate_for_bitwise()?;235 let exp = v2.truncate_for_bitwise()? % 64;236237 if exp >= 1 && base >= (1i64 << (63 - exp as u32)) {238 bail!("left shift would overflow")239 }240 Val::try_num(base.wrapping_shl(exp as u32) as f64)?241 }242 (Num(v1), Rhs, Num(v2)) => {243 if v2.get() < 0.0 {244 bail!("shift by negative exponent")245 }246 let exp = ((v2.get() as i64) & 63) as u32;247 Val::try_num(v1.truncate_for_bitwise()?.wrapping_shr(exp) as f64)?248 }249250 // Bigint X Bigint251 _ => bail!(BinaryOperatorDoesNotOperateOnValues(252 op,253 a.value_type(),254 b.value_type(),255 )),256 })257}crates/jrsonnet-evaluator/src/function/native.rsdiffbeforeafterboth--- 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<O> {
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<Val> {
- bail!("can only convert functions from jsonnet to native")
- }
+ }
+ impl<$($gen,)* O> FromUntyped for NativeFn<($($gen,)* O,)> {
fn from_untyped(untyped: Val) -> Result<Self> {
let func = FuncVal::from_untyped(untyped)?;
Ok(Self(
crates/jrsonnet-evaluator/src/stdlib/format.rsdiffbeforeafterboth--- 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,
};
crates/jrsonnet-evaluator/src/typed/conversions.rsdiffbeforeafterboth--- 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<K: Trace>(PhantomData<fn() -> K>);
-impl<K> ThunkMapper<Val> for FromUntyped<K>
+struct ThunkFromUntyped<K: Trace>(PhantomData<fn() -> K>);
+impl<K> ThunkMapper<Val> for ThunkFromUntyped<K>
where
- K: Typed + Trace,
+ K: Typed + FromUntyped + Trace,
{
type Output = K;
@@ -26,12 +26,29 @@
K::from_untyped(from)
}
}
-impl<K: Trace> Default for FromUntyped<K> {
+impl<K: Trace> Default for ThunkFromUntyped<K> {
fn default() -> Self {
Self(PhantomData)
}
}
+#[derive(Trace)]
+struct ThunkIntoUntyped<K: Trace>(PhantomData<fn() -> K>);
+impl<K> ThunkMapper<K> for ThunkIntoUntyped<K>
+where
+ K: Typed + Trace + IntoUntyped,
+{
+ type Output = Val;
+ fn map(self, from: K) -> Result<Self::Output> {
+ K::into_untyped(from)
+ }
+}
+impl<K: Trace> Default for ThunkIntoUntyped<K> {
+ fn default() -> Self {
+ Self(PhantomData)
+ }
+}
+
pub trait TypedObj: Typed {
fn serialize(self, out: &mut ObjValueBuilder) -> Result<()>;
fn parse(obj: &ObjValue) -> Result<Self>;
@@ -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<Val>;
fn into_lazy_untyped(typed: Self) -> Thunk<Val> {
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<Val>;
+}
+impl<T> IntoUntypedResult for T
+where
+ T: IntoUntyped,
+{
+ fn into_untyped_result(typed: Self) -> Result<Val> {
+ T::into_untyped(typed)
+ }
+}
+
+pub trait FromUntyped: Typed {
fn from_untyped(untyped: Val) -> Result<Self>;
fn from_lazy_untyped(lazy: Thunk<Val>) -> Result<Self> {
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<Val> {
- 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<T> IntoUntyped for Thunk<T>
+where
+ T: Typed + IntoUntyped + Trace + Clone,
+{
fn into_untyped(typed: Self) -> Result<Val> {
T::into_untyped(typed.evaluate()?)
- }
-
- fn from_untyped(untyped: Val) -> Result<Self> {
- Self::from_lazy_untyped(Thunk::evaluated(untyped))
}
-
fn provides_lazy() -> bool {
true
}
fn into_lazy_untyped(inner: Self) -> Thunk<Val> {
- #[derive(Trace)]
- struct IntoUntyped<K: Trace>(PhantomData<fn() -> K>);
- impl<K> ThunkMapper<K> for IntoUntyped<K>
- where
- K: Typed + Trace,
- {
- type Output = Val;
+ inner.map(<ThunkIntoUntyped<T>>::default())
+ }
+}
- fn map(self, from: K) -> Result<Self::Output> {
- K::into_untyped(from)
- }
- }
- impl<K: Trace> Default for IntoUntyped<K> {
- fn default() -> Self {
- Self(PhantomData)
- }
- }
- inner.map(<IntoUntyped<T>>::default())
+impl<T> FromUntyped for Thunk<T>
+where
+ T: Typed + FromUntyped + Trace + Clone,
+{
+ fn from_untyped(untyped: Val) -> Result<Self> {
+ Self::from_lazy_untyped(Thunk::evaluated(untyped))
}
fn wants_lazy() -> bool {
@@ -116,7 +135,7 @@
}
fn from_lazy_untyped(inner: Thunk<Val>) -> Result<Self> {
- Ok(inner.map(<FromUntyped<T>>::default()))
+ Ok(inner.map(<ThunkFromUntyped<T>>::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<Self> {
<Self as Typed>::TYPE.check(&value)?;
match value {
@@ -145,6 +166,8 @@
_ => unreachable!(),
}
}
+ }
+ impl IntoUntyped for $ty {
fn into_untyped(value: Self) -> Result<Val> {
Ok(Val::Num(value.into()))
}
@@ -183,7 +206,9 @@
Some(MIN as f64),
Some(MAX as f64),
);
+ }
+ impl<const MIN: $ty, const MAX: $ty> FromUntyped for $name<MIN, MAX> {
fn from_untyped(value: Val) -> Result<Self> {
<Self as Typed>::TYPE.check(&value)?;
match value {
@@ -201,7 +226,9 @@
_ => unreachable!(),
}
}
+ }
+ impl<const MIN: $ty, const MAX: $ty> IntoUntyped for $name<MIN, MAX> {
#[allow(clippy::cast_lossless)]
fn into_untyped(value: Self) -> Result<Val> {
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<Val> {
Ok(Val::try_num(value)?)
}
-
+}
+impl FromUntyped for f64 {
fn from_untyped(value: Val) -> Result<Self> {
<Self as Typed>::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<Val> {
Ok(Val::try_num(value.0)?)
}
-
+}
+impl FromUntyped for PositiveF64 {
fn from_untyped(value: Val) -> Result<Self> {
<Self as Typed>::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<Val> {
Ok(Val::try_num(value)?)
}
-
+}
+impl FromUntyped for usize {
fn from_untyped(value: Val) -> Result<Self> {
<Self as Typed>::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<Val> {
Ok(Val::string(value))
}
-
+}
+impl FromUntyped for IStr {
fn from_untyped(value: Val) -> Result<Self> {
<Self as Typed>::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<Val> {
Ok(Val::string(value))
}
-
+}
+impl FromUntyped for String {
fn from_untyped(value: Val) -> Result<Self> {
<Self as Typed>::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<Val> {
Ok(Val::Str(value))
}
-
+}
+impl FromUntyped for StrValue {
fn from_untyped(value: Val) -> Result<Self> {
<Self as Typed>::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<Val> {
Ok(Val::string(value))
}
-
+}
+impl FromUntyped for char {
fn from_untyped(value: Val) -> Result<Self> {
<Self as Typed>::TYPE.check(&value)?;
match value {
@@ -338,12 +379,14 @@
}
}
+// TODO: View into vec using ArrayLike?
impl<T> Typed for Vec<T>
where
T: Typed,
{
const TYPE: &'static ComplexValType = &ComplexValType::ArrayRef(T::TYPE);
-
+}
+impl<T: Typed + IntoUntyped> IntoUntyped for Vec<T> {
fn into_untyped(value: Self) -> Result<Val> {
Ok(Val::Arr(
value
@@ -352,7 +395,8 @@
.collect::<Result<ArrValue>>()?,
))
}
-
+}
+impl<T: Typed + FromUntyped> FromUntyped for Vec<T> {
fn from_untyped(value: Val) -> Result<Self> {
let Val::Arr(a) = value else {
<Self as Typed>::TYPE.check(&value)?;
@@ -369,9 +413,19 @@
}
}
-impl<K: Typed + Ord, V: Typed> Typed for BTreeMap<K, V> {
+// TODO: View into BTreeMap using ObjectCore?
+impl<K, V> Typed for BTreeMap<K, V>
+where
+ K: Typed + Ord,
+ V: Typed,
+{
const TYPE: &'static ComplexValType = &ComplexValType::AttrsOf(V::TYPE);
-
+}
+impl<K, V> IntoUntyped for BTreeMap<K, V>
+where
+ K: Typed + Ord + IntoUntyped,
+ V: Typed + IntoUntyped,
+{
fn into_untyped(typed: Self) -> Result<Val> {
let mut out = ObjValueBuilder::with_capacity(typed.len());
for (k, v) in typed {
@@ -383,7 +437,12 @@
}
Ok(Val::Obj(out.build()))
}
-
+}
+impl<K, V> FromUntyped for BTreeMap<K, V>
+where
+ K: FromUntyped + Ord,
+ V: FromUntyped,
+{
fn from_untyped(value: Val) -> Result<Self> {
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<Val> {
Ok(typed)
}
+}
+impl FromUntyped for Val {
fn from_untyped(untyped: Val) -> Result<Self> {
Ok(untyped)
}
}
-// Hack
#[doc(hidden)]
impl<T> Typed for Result<T>
where
T: Typed,
{
const TYPE: &'static ComplexValType = &ComplexValType::Any;
-
- fn into_untyped(_typed: Self) -> Result<Val> {
- panic!("do not use this conversion")
- }
-
- fn from_untyped(_untyped: Val) -> Result<Self> {
- panic!("do not use this conversion")
- }
-
- fn into_result(typed: Self) -> Result<Val> {
+}
+impl<T: IntoUntyped> IntoUntypedResult for Result<T> {
+ fn into_untyped_result(typed: Self) -> Result<Val> {
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<Val> {
Ok(Val::Arr(ArrValue::bytes(value)))
}
-
+}
+impl FromUntyped for IBytes {
fn from_untyped(value: Val) -> Result<Self> {
let Val::Arr(a) = &value else {
<Self as Typed>::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<Val> {
Ok(Val::Num(NumValue::new(-1.0).expect("finite")))
}
-
+}
+impl FromUntyped for M1 {
fn from_untyped(value: Val) -> Result<Self> {
<Self as Typed>::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<Val> {
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<Self> {
$(
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<Val> {
Ok(Val::Arr(value))
}
-
+}
+impl FromUntyped for ArrValue {
fn from_untyped(value: Val) -> Result<Self> {
<Self as Typed>::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<Val> {
Ok(Val::Func(value))
}
-
- fn from_untyped(value: Val) -> Result<Self> {
- <Self as Typed>::TYPE.check(&value)?;
- match value {
- Val::Func(a) => Ok(a),
- _ => unreachable!(),
- }
- }
}
-
-impl Typed for Cc<FuncDesc> {
- const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Func);
-
- fn into_untyped(value: Self) -> Result<Val> {
- Ok(Val::Func(FuncVal::Normal(value)))
- }
-
+impl FromUntyped for FuncVal {
fn from_untyped(value: Val) -> Result<Self> {
<Self as Typed>::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<Val> {
Ok(Val::Obj(value))
}
-
+}
+impl FromUntyped for ObjValue {
fn from_untyped(value: Val) -> Result<Self> {
<Self as Typed>::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<Val> {
Ok(Val::Bool(value))
}
-
+}
+impl FromUntyped for bool {
fn from_untyped(value: Val) -> Result<Self> {
<Self as Typed>::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<Val> {
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<Self> {
<Self as Typed>::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<Val> {
Ok(Val::Null)
}
-
+}
+impl FromUntyped for Null {
fn from_untyped(value: Val) -> Result<Self> {
<Self as Typed>::TYPE.check(&value)?;
Ok(Self)
@@ -661,11 +724,19 @@
{
const TYPE: &'static ComplexValType =
&ComplexValType::UnionRef(&[&ComplexValType::Simple(ValType::Null), T::TYPE]);
-
+}
+impl<T> IntoUntyped for Option<T>
+where
+ T: Typed + IntoUntyped,
+{
fn into_untyped(typed: Self) -> Result<Val> {
typed.map_or_else(|| Ok(Val::Null), |v| T::into_untyped(v))
}
-
+}
+impl<T> FromUntyped for Option<T>
+where
+ T: Typed + FromUntyped,
+{
fn from_untyped(untyped: Val) -> Result<Self> {
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<Val> {
Ok(Val::Num(typed))
}
-
+}
+impl FromUntyped for NumValue {
fn from_untyped(untyped: Val) -> Result<Self> {
Self::TYPE.check(&untyped)?;
match untyped {
crates/jrsonnet-interner/src/names.rsdiffbeforeafterboth--- a/crates/jrsonnet-interner/src/names.rs
+++ b/crates/jrsonnet-interner/src/names.rs
@@ -0,0 +1 @@
+
crates/jrsonnet-macros/src/lib.rsdiffbeforeafterboth--- 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<I>(attrs: &[Attribute], ident: I) -> Result<bool>
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("<unnamed>", 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<Thunk<Val>>]) -> Result<Val> {
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
crates/jrsonnet-macros/src/names.rsdiffbeforeafterboth--- 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 {
crates/jrsonnet-macros/src/typed.rsdiffbeforeafterboth--- 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<Self> {
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<Val> {
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,
crates/jrsonnet-stdlib/src/arrays.rsdiffbeforeafterboth--- 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 {
crates/jrsonnet-stdlib/src/keyf.rsdiffbeforeafterboth--- 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<Self> {
FuncVal::from_untyped(untyped).map(Self::new)
- }
-
- fn into_untyped(_typed: Self) -> Result<Val> {
- unreachable!("unused, todo: port split of Typed trait from #193")
}
}
crates/jrsonnet-stdlib/src/manifest/ini.rsdiffbeforeafterboth--- 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;
crates/jrsonnet-stdlib/src/manifest/xml.rsdiffbeforeafterboth--- 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<Val> {
- unreachable!("not used, reserved for parseXML?")
- }
-
+}
+impl FromUntyped for JSONMLValue {
fn from_untyped(untyped: Val) -> Result<Self> {
let val = <Either![ArrValue, String]>::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,
crates/jrsonnet-stdlib/src/strings.rsdiffbeforeafterboth--- 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,
};
tests/tests/builtin.rsdiffbeforeafterboth--- 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;
tests/tests/typed_obj.rsdiffbeforeafterboth--- 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<T: Typed + PartialEq + Debug + Clone>(value: T) -> Result<()> {
+fn test_roundtrip<T: Typed + PartialEq + Debug + Clone + FromUntyped + IntoUntyped>(
+ value: T,
+) -> Result<()> {
let untyped = T::into_untyped(value.clone())?;
let value2 = T::from_untyped(untyped.clone())?;
ensure_eq!(value, value2);