difftreelog
feat unify Arg and Typed handling for Thunk
in: master
8 files changed
crates/jrsonnet-evaluator/src/ctx.rsdiffbeforeafterboth81 #[must_use]81 #[must_use]82 pub fn into_future(self, ctx: Pending<Self>) -> Self {82 pub fn into_future(self, ctx: Pending<Self>) -> Self {83 {83 {84 ctx.0.borrow_mut().replace(self);84 ctx.clone().fill(self);85 }85 }86 ctx.unwrap()86 ctx.unwrap()87 }87 }crates/jrsonnet-evaluator/src/dynamic.rsdiffbeforeafterboth1use std::cell::RefCell;1use std::cell::OnceCell;223use jrsonnet_gcmodule::{Cc, Trace};3use jrsonnet_gcmodule::{Cc, Trace};45use crate::{error::ErrorKind::InfiniteRecursionDetected, throw, val::ThunkValue, Result, Thunk};465// TODO: Replace with OnceCell once in std7// TODO: Replace with OnceCell once in std6#[derive(Clone, Trace)]8#[derive(Clone, Trace)]7pub struct Pending<V: Trace + 'static>(pub Cc<RefCell<Option<V>>>);9pub struct Pending<V: Trace + 'static>(pub Cc<OnceCell<V>>);8impl<T: Trace + 'static> Pending<T> {10impl<T: Trace + 'static> Pending<T> {9 pub fn new() -> Self {11 pub fn new() -> Self {10 Self(Cc::new(RefCell::new(None)))12 Self(Cc::new(OnceCell::new()))11 }13 }12 pub fn new_filled(v: T) -> Self {14 pub fn new_filled(v: T) -> Self {15 let cell = OnceCell::new();16 let _ = cell.set(v);13 Self(Cc::new(RefCell::new(Some(v))))17 Self(Cc::new(cell))14 }18 }15 /// # Panics19 /// # Panics16 /// If wrapper is filled already20 /// If wrapper is filled already17 pub fn fill(self, value: T) {21 pub fn fill(self, value: T) {18 assert!(self.0.borrow().is_none(), "wrapper is filled already");19 self.0.borrow_mut().replace(value);22 self.023 .set(value)24 .map_err(|_| ())25 .expect("wrapper is filled already")20 }26 }21}27}22impl<T: Clone + Trace + 'static> Pending<T> {28impl<T: Clone + Trace + 'static> Pending<T> {23 /// # Panics29 /// # Panics24 /// If wrapper is not yet filled30 /// If wrapper is not yet filled25 pub fn unwrap(&self) -> T {31 pub fn unwrap(&self) -> T {26 self.0.borrow().as_ref().cloned().unwrap()32 self.0.get().cloned().expect("pending was not filled")27 }33 }34 pub fn try_get(&self) -> Option<T> {35 self.0.get().cloned()36 }28}37}3839impl<T: Trace + Clone> ThunkValue for Pending<T> {40 type Output = T;4142 fn get(self: Box<Self>) -> Result<Self::Output> {43 let Some(value) = self.0.get() else {44 throw!(InfiniteRecursionDetected);45 };46 Ok(value.clone())47 }48}294930impl<T: Trace + 'static> Default for Pending<T> {50impl<T: Trace + 'static> Default for Pending<T> {31 fn default() -> Self {51 fn default() -> Self {32 Self::new()52 Self::new()33 }53 }34}54}5556impl<T: Trace + Clone> Into<Thunk<T>> for Pending<T> {57 fn into(self) -> Thunk<T> {58 Thunk::new(self)59 }60}3561crates/jrsonnet-evaluator/src/function/arglike.rsdiffbeforeafterboth48where48where49 T: Typed + Clone,49 T: Typed + Clone,50{50{51 fn evaluate_arg(&self, _ctx: Context, _tailstrict: bool) -> Result<Thunk<Val>> {51 fn evaluate_arg(&self, _ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {52 if T::provides_lazy() && !tailstrict {53 return Ok(T::into_lazy_untyped(self.clone()));54 }52 let val = T::into_untyped(self.clone())?;55 let val = T::into_untyped(self.clone())?;53 Ok(Thunk::evaluated(val))56 Ok(Thunk::evaluated(val))54 }57 }55}58}56impl<T> OptionalContext for T where T: Typed + Clone {}59impl<T> OptionalContext for T where T: Typed + Clone {}5758impl ArgLike for Thunk<Val> {59 fn evaluate_arg(&self, _ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {60 if tailstrict {61 self.force()?;62 }63 Ok(self.clone())64 }65}66impl OptionalContext for Thunk<Val> {}676068#[derive(Clone, Trace)]61#[derive(Clone, Trace)]69pub enum TlaArg {62pub enum TlaArg {70 String(IStr),63 String(IStr),71 Code(LocExpr),64 Code(LocExpr),72 Val(Val),65 Val(Val),66 Lazy(Thunk<Val>),73}67}74impl ArgLike for TlaArg {68impl ArgLike for TlaArg {75 fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {69 fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {84 })78 })85 }),79 }),86 TlaArg::Val(val) => Ok(Thunk::evaluated(val.clone())),80 TlaArg::Val(val) => Ok(Thunk::evaluated(val.clone())),81 TlaArg::Lazy(lazy) => Ok(lazy.clone()),87 }82 }88 }83 }89}84}crates/jrsonnet-evaluator/src/obj.rsdiffbeforeafterboth16 gc::{GcHashMap, GcHashSet, TraceBox},16 gc::{GcHashMap, GcHashSet, TraceBox},17 operator::evaluate_add_op,17 operator::evaluate_add_op,18 tb, throw, MaybeUnbound, Result, State, Thunk, Unbound, Val,18 tb, throw,19 val::ThunkValue,20 MaybeUnbound, Result, State, Thunk, Unbound, Val,19};21};2022crates/jrsonnet-evaluator/src/typed/conversions.rsdiffbeforeafterboth1use std::ops::Deref;1use std::{collections::BTreeMap, marker::PhantomData, ops::Deref};223use jrsonnet_gcmodule::Cc;3use jrsonnet_gcmodule::{Cc, Trace};4use jrsonnet_interner::{IBytes, IStr};4use jrsonnet_interner::{IBytes, IStr};5pub use jrsonnet_macros::Typed;5pub use jrsonnet_macros::Typed;6use jrsonnet_types::{ComplexValType, ValType};6use jrsonnet_types::{ComplexValType, ValType};11 function::{native::NativeDesc, FuncDesc, FuncVal},11 function::{native::NativeDesc, FuncDesc, FuncVal},12 throw,12 throw,13 typed::CheckType,13 typed::CheckType,14 val::{IndexableVal, StrValue},14 val::{IndexableVal, StrValue, ThunkMapper},15 ObjValue, ObjValueBuilder, Val,15 ObjValue, ObjValueBuilder, Thunk, Val,16};16};1718#[derive(Trace)]19struct FromUntyped<K: Trace>(PhantomData<fn() -> K>);20impl<K> ThunkMapper<Val> for FromUntyped<K>21where22 K: Typed + Trace,23{24 type Output = K;2526 fn map(self, from: Val) -> Result<Self::Output> {27 K::from_untyped(from)28 }29}30impl<K: Trace> Default for FromUntyped<K> {31 fn default() -> Self {32 Self(PhantomData)33 }34}173518pub trait TypedObj: Typed {36pub trait TypedObj: Typed {19 fn serialize(self, out: &mut ObjValueBuilder) -> Result<()>;37 fn serialize(self, out: &mut ObjValueBuilder) -> Result<()>;28pub trait Typed: Sized {46pub trait Typed: Sized {29 const TYPE: &'static ComplexValType;47 const TYPE: &'static ComplexValType;30 fn into_untyped(typed: Self) -> Result<Val>;48 fn into_untyped(typed: Self) -> Result<Val>;49 fn into_lazy_untyped(typed: Self) -> Thunk<Val> {50 Thunk::from(Self::into_untyped(typed))51 }31 fn from_untyped(untyped: Val) -> Result<Self>;52 fn from_untyped(untyped: Val) -> Result<Self>;53 fn from_lazy_untyped(lazy: Thunk<Val>) -> Result<Self> {54 Self::from_untyped(lazy.evaluate()?)55 }5657 // Whatever caller should use `into_lazy_untyped` instead of `into_untyped`58 fn provides_lazy() -> bool {59 false60 }6162 // Whatever caller should use `from_lazy_untyped` instead of `from_untyped` when possible63 fn wants_lazy() -> bool {64 false65 }326633 /// Hack to make builtins be able to return non-result values, and make macros able to convert those values to result67 /// Hack to make builtins be able to return non-result values, and make macros able to convert those values to result34 /// This method returns identity in impl Typed for Result, and should not be overriden68 /// This method returns identity in impl Typed for Result, and should not be overriden39 }73 }40}74}7576impl<T> Typed for Thunk<T>77where78 T: Typed + Trace + Clone,79{80 const TYPE: &'static ComplexValType = &ComplexValType::Lazy(T::TYPE);8182 fn into_untyped(typed: Self) -> Result<Val> {83 T::into_untyped(typed.evaluate()?)84 }8586 fn from_untyped(untyped: Val) -> Result<Self> {87 Self::from_lazy_untyped(Thunk::evaluated(untyped))88 }8990 fn provides_lazy() -> bool {91 true92 }9394 fn into_lazy_untyped(inner: Self) -> Thunk<Val> {95 #[derive(Trace)]96 struct IntoUntyped<K: Trace>(PhantomData<fn() -> K>);97 impl<K> ThunkMapper<K> for IntoUntyped<K>98 where99 K: Typed + Trace,100 {101 type Output = Val;102103 fn map(self, from: K) -> Result<Self::Output> {104 K::into_untyped(from)105 }106 }107 impl<K: Trace> Default for IntoUntyped<K> {108 fn default() -> Self {109 Self(PhantomData)110 }111 }112 inner.map(<IntoUntyped<T>>::default())113 }114115 fn wants_lazy() -> bool {116 true117 }118119 fn from_lazy_untyped(inner: Thunk<Val>) -> Result<Self> {120 Ok(inner.map(<FromUntyped<T>>::default()))121 }122}4112342const MAX_SAFE_INTEGER: f64 = ((1u64 << (f64::MANTISSA_DIGITS + 1)) - 1) as f64;124const MAX_SAFE_INTEGER: f64 = ((1u64 << (f64::MANTISSA_DIGITS + 1)) - 1) as f64;43125crates/jrsonnet-evaluator/src/typed/mod.rsdiffbeforeafterboth252 }252 }253 Ok(())253 Ok(())254 }254 }255 Self::Lazy(_lazy) => Ok(()),255 }256 }256 }257 }257}258}crates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth88 }88 }89}89}9091pub trait ThunkMapper<Input>: Trace {92 type Output;93 fn map(self, from: Input) -> Result<Self::Output>;94}95impl<Input> Thunk<Input>96where97 Input: Trace + Clone,98{99 pub fn map<M>(self, mapper: M) -> Thunk<M::Output>100 where101 M: ThunkMapper<Input>,102 M::Output: Trace,103 {104 #[derive(Trace)]105 struct Mapped<Input: Trace, Mapper: Trace> {106 inner: Thunk<Input>,107 mapper: Mapper,108 }109 impl<Input, Mapper> ThunkValue for Mapped<Input, Mapper>110 where111 Input: Trace + Clone,112 Mapper: ThunkMapper<Input>,113 {114 type Output = Mapper::Output;115116 fn get(self: Box<Self>) -> Result<Self::Output> {117 let value = self.inner.evaluate()?;118 let mapped = self.mapper.map(value)?;119 Ok(mapped)120 }121 }122123 Thunk::new(Mapped::<Input, M> {124 inner: self,125 mapper,126 })127 }128}129130impl<T: Trace> From<Result<T>> for Thunk<T> {131 fn from(value: Result<T>) -> Self {132 match value {133 Ok(o) => Self::evaluated(o),134 Err(e) => Self::errored(e),135 }136 }137}9013891type CacheKey = (Option<WeakObjValue>, Option<WeakObjValue>);139type CacheKey = (Option<WeakObjValue>, Option<WeakObjValue>);92140272 Self::Flat(value.into())320 Self::Flat(value.into())273 }321 }274}322}323impl From<IStr> for StrValue {324 fn from(value: IStr) -> Self {325 Self::Flat(value)326 }327}275impl Display for StrValue {328impl Display for StrValue {276 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {329 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {277 match self {330 match self {crates/jrsonnet-types/src/lib.rsdiffbeforeafterboth128 Array(Box<ComplexValType>),128 Array(Box<ComplexValType>),129 ArrayRef(&'static ComplexValType),129 ArrayRef(&'static ComplexValType),130 ObjectRef(&'static [(&'static str, &'static ComplexValType)]),130 ObjectRef(&'static [(&'static str, &'static ComplexValType)]),131 AttrsOf(&'static ComplexValType),131 Union(Vec<ComplexValType>),132 Union(Vec<ComplexValType>),132 UnionRef(&'static [&'static ComplexValType]),133 UnionRef(&'static [&'static ComplexValType]),133 Sum(Vec<ComplexValType>),134 Sum(Vec<ComplexValType>),134 SumRef(&'static [&'static ComplexValType]),135 SumRef(&'static [&'static ComplexValType]),136 Lazy(&'static ComplexValType),135}137}136138137impl From<ValType> for ComplexValType {139impl From<ValType> for ComplexValType {195 }197 }196 write!(f, "}}")?;198 write!(f, "}}")?;197 }199 }200 ComplexValType::AttrsOf(a) => {201 if matches!(a, ComplexValType::Any) {202 write!(f, "object")?;203 } else {204 write!(f, "AttrsOf<{a}>")?;205 }206 }198 ComplexValType::Union(v) => write_union(f, true, v.iter())?,207 ComplexValType::Union(v) => write_union(f, true, v.iter())?,199 ComplexValType::UnionRef(v) => write_union(f, true, v.iter().copied())?,208 ComplexValType::UnionRef(v) => write_union(f, true, v.iter().copied())?,200 ComplexValType::Sum(v) => write_union(f, false, v.iter())?,209 ComplexValType::Sum(v) => write_union(f, false, v.iter())?,201 ComplexValType::SumRef(v) => write_union(f, false, v.iter().copied())?,210 ComplexValType::SumRef(v) => write_union(f, false, v.iter().copied())?,211 ComplexValType::Lazy(lazy) => write!(f, "Lazy<{lazy}>")?,202 };212 };203 Ok(())213 Ok(())204 }214 }