--- a/crates/jrsonnet-evaluator/src/val.rs +++ b/crates/jrsonnet-evaluator/src/val.rs @@ -11,7 +11,9 @@ stdlib::manifest::{ manifest_json_ex, manifest_yaml_ex, ManifestJsonOptions, ManifestType, ManifestYamlOptions, }, - throw, ObjValue, Result, State, Unbound, WeakObjValue, + throw, + typed::BoundedUsize, + ObjValue, Result, State, Unbound, WeakObjValue, }; pub trait ThunkValue: Trace { @@ -459,6 +461,51 @@ Str(IStr), Arr(ArrValue), } +impl IndexableVal { + pub fn slice( + self, + index: Option>, + end: Option>, + step: Option>, + ) -> Result { + match &self { + IndexableVal::Str(s) => { + let index = index.as_deref().copied().unwrap_or(0); + let end = end.as_deref().copied().unwrap_or(usize::MAX); + let step = step.as_deref().copied().unwrap_or(1); + + if index >= end { + return Ok(Self::Str("".into())); + } + + Ok(Self::Str( + (s.chars() + .skip(index) + .take(end - index) + .step_by(step) + .collect::()) + .into(), + )) + } + IndexableVal::Arr(arr) => { + let index = index.as_deref().copied().unwrap_or(0); + let end = end.as_deref().copied().unwrap_or(usize::MAX).min(arr.len()); + let step = step.as_deref().copied().unwrap_or(1); + + if index >= end { + return Ok(Self::Arr(ArrValue::new_eager())); + } + + Ok(Self::Arr(ArrValue::Slice(Box::new(Slice { + inner: arr.clone(), + from: index as u32, + to: end as u32, + step: step as u32, + })))) + } + } + } +} #[derive(Debug, Clone, Trace)] pub enum Val { @@ -471,6 +518,15 @@ Func(FuncVal), } +impl From for Val { + fn from(v: IndexableVal) -> Self { + match v { + IndexableVal::Str(s) => Self::Str(s), + IndexableVal::Arr(a) => Self::Arr(a), + } + } +} + #[cfg(target_pointer_width = "64")] static_assertions::assert_eq_size!(Val, [u8; 32]);