git.delta.rocks / jrsonnet / refs/commits / f66194917e5d

difftreelog

feat unify Arg and Typed handling for Thunk

Yaroslav Bolyukin2023-07-27parent: #a85a211.patch.diff
in: master

8 files changed

modifiedcrates/jrsonnet-evaluator/src/ctx.rsdiffbeforeafterboth
81 #[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 }
modifiedcrates/jrsonnet-evaluator/src/dynamic.rsdiffbeforeafterboth
1use std::cell::RefCell;1use std::cell::OnceCell;
22
3use jrsonnet_gcmodule::{Cc, Trace};3use jrsonnet_gcmodule::{Cc, Trace};
4
5use crate::{error::ErrorKind::InfiniteRecursionDetected, throw, val::ThunkValue, Result, Thunk};
46
5// TODO: Replace with OnceCell once in std7// TODO: Replace with OnceCell once in std
6#[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 /// # Panics
16 /// If wrapper is filled already20 /// If wrapper is filled already
17 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.0
23 .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 /// # Panics
24 /// If wrapper is not yet filled30 /// If wrapper is not yet filled
25 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}
38
39impl<T: Trace + Clone> ThunkValue for Pending<T> {
40 type Output = T;
41
42 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}
2949
30impl<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}
55
56impl<T: Trace + Clone> Into<Thunk<T>> for Pending<T> {
57 fn into(self) -> Thunk<T> {
58 Thunk::new(self)
59 }
60}
3561
modifiedcrates/jrsonnet-evaluator/src/function/arglike.rsdiffbeforeafterboth
48where48where
49 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 {}
57
58impl 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> {}
6760
68#[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}
modifiedcrates/jrsonnet-evaluator/src/obj.rsdiffbeforeafterboth
16 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};
2022
modifiedcrates/jrsonnet-evaluator/src/typed/conversions.rsdiffbeforeafterboth
1use std::ops::Deref;1use std::{collections::BTreeMap, marker::PhantomData, ops::Deref};
22
3use 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};
17
18#[derive(Trace)]
19struct FromUntyped<K: Trace>(PhantomData<fn() -> K>);
20impl<K> ThunkMapper<Val> for FromUntyped<K>
21where
22 K: Typed + Trace,
23{
24 type Output = K;
25
26 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}
1735
18pub 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 }
56
57 // Whatever caller should use `into_lazy_untyped` instead of `into_untyped`
58 fn provides_lazy() -> bool {
59 false
60 }
61
62 // Whatever caller should use `from_lazy_untyped` instead of `from_untyped` when possible
63 fn wants_lazy() -> bool {
64 false
65 }
3266
33 /// 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 result
34 /// 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 overriden
39 }73 }
40}74}
75
76impl<T> Typed for Thunk<T>
77where
78 T: Typed + Trace + Clone,
79{
80 const TYPE: &'static ComplexValType = &ComplexValType::Lazy(T::TYPE);
81
82 fn into_untyped(typed: Self) -> Result<Val> {
83 T::into_untyped(typed.evaluate()?)
84 }
85
86 fn from_untyped(untyped: Val) -> Result<Self> {
87 Self::from_lazy_untyped(Thunk::evaluated(untyped))
88 }
89
90 fn provides_lazy() -> bool {
91 true
92 }
93
94 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 where
99 K: Typed + Trace,
100 {
101 type Output = Val;
102
103 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 }
114
115 fn wants_lazy() -> bool {
116 true
117 }
118
119 fn from_lazy_untyped(inner: Thunk<Val>) -> Result<Self> {
120 Ok(inner.map(<FromUntyped<T>>::default()))
121 }
122}
41123
42const 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;
43125
modifiedcrates/jrsonnet-evaluator/src/typed/mod.rsdiffbeforeafterboth
252 }252 }
253 Ok(())253 Ok(())
254 }254 }
255 Self::Lazy(_lazy) => Ok(()),
255 }256 }
256 }257 }
257}258}
modifiedcrates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth
88 }88 }
89}89}
90
91pub trait ThunkMapper<Input>: Trace {
92 type Output;
93 fn map(self, from: Input) -> Result<Self::Output>;
94}
95impl<Input> Thunk<Input>
96where
97 Input: Trace + Clone,
98{
99 pub fn map<M>(self, mapper: M) -> Thunk<M::Output>
100 where
101 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 where
111 Input: Trace + Clone,
112 Mapper: ThunkMapper<Input>,
113 {
114 type Output = Mapper::Output;
115
116 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 }
122
123 Thunk::new(Mapped::<Input, M> {
124 inner: self,
125 mapper,
126 })
127 }
128}
129
130impl<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}
90138
91type CacheKey = (Option<WeakObjValue>, Option<WeakObjValue>);139type CacheKey = (Option<WeakObjValue>, Option<WeakObjValue>);
92140
272 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 {
modifiedcrates/jrsonnet-types/src/lib.rsdiffbeforeafterboth
128 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}
136138
137impl 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 }