git.delta.rocks / jrsonnet / refs/commits / 4c008687f967

difftreelog

perf lazy slice

Yaroslav Bolyukin2022-04-20parent: #9c0fa01.patch.diff
in: master

5 files changed

modifiedcrates/jrsonnet-evaluator/src/builtin/mod.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/builtin/mod.rs
+++ b/crates/jrsonnet-evaluator/src/builtin/mod.rs
@@ -43,33 +43,45 @@
 
 pub fn std_slice(
 	indexable: IndexableVal,
-	index: Option<usize>,
-	end: Option<usize>,
-	step: Option<usize>,
+	index: Option<BoundedUsize<0, { i32::MAX as usize }>>,
+	end: Option<BoundedUsize<0, { i32::MAX as usize }>>,
+	step: Option<BoundedUsize<1, { i32::MAX as usize }>>,
 ) -> Result<Val> {
-	let index = index.unwrap_or(0);
-	let end = end.unwrap_or_else(|| match &indexable {
-		IndexableVal::Str(_) => usize::MAX,
-		IndexableVal::Arr(v) => v.len(),
-	});
-	let step = step.unwrap_or(1);
 	match &indexable {
-		IndexableVal::Str(s) => Ok(Val::Str(
+		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(Val::Str("".into()));
+			}
+
+			Ok(Val::Str(
 			(s.chars()
 				.skip(index)
 				.take(end - index)
 				.step_by(step)
 				.collect::<String>())
 			.into(),
-		)),
-		IndexableVal::Arr(arr) => Ok(Val::Arr(
-			(arr.iter()
-				.skip(index)
-				.take(end - index)
-				.step_by(step)
-				.collect::<Result<Vec<Val>>>()?)
-			.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(Val::Arr(ArrValue::new_eager()));
+			}
+
+			Ok(Val::Arr(ArrValue::Slice(Box::new(Slice {
+				inner: arr.clone(),
+				from: index as u32,
+				to: end as u32,
+				step: step as u32,
+			}))))
+		}
 	}
 }
 
@@ -221,9 +233,9 @@
 #[jrsonnet_macros::builtin]
 fn builtin_slice(
 	indexable: IndexableVal,
-	index: Option<usize>,
-	end: Option<usize>,
-	step: Option<usize>,
+	index: Option<BoundedUsize<0, { i32::MAX as usize }>>,
+	end: Option<BoundedUsize<0, { i32::MAX as usize }>>,
+	step: Option<BoundedUsize<1, { i32::MAX as usize }>>,
 ) -> Result<Any> {
 	std_slice(indexable, index, end, step).map(Any)
 }
modifiedcrates/jrsonnet-evaluator/src/error.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/error.rs
+++ b/crates/jrsonnet-evaluator/src/error.rs
@@ -191,3 +191,10 @@
 		return Err($e.into())
 	};
 }
+
+#[macro_export]
+macro_rules! throw_runtime {
+	($($tt:tt)*) => {
+		return Err($crate::error::Error::RuntimeError(format!($($tt)*).into()).into())
+	};
+}
modifiedcrates/jrsonnet-evaluator/src/evaluate/mod.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/evaluate/mod.rs
+++ b/crates/jrsonnet-evaluator/src/evaluate/mod.rs
@@ -665,23 +665,28 @@
 		}
 		Slice(value, desc) => {
 			let indexable = evaluate(context.clone(), value)?;
+			let loc = CallLocation::new(loc);
 
-			fn parse_num(
+			fn parse_idx<const MIN: usize>(
+				loc: CallLocation,
 				context: &Context,
-				expr: Option<&LocExpr>,
+				expr: &Option<LocExpr>,
 				desc: &'static str,
-			) -> Result<Option<usize>> {
-				Ok(match expr {
-					Some(s) => evaluate(context.clone(), s)?
-						.try_cast_nullable_num(desc)?
-						.map(|v| v as usize),
-					None => None,
-				})
+			) -> Result<Option<BoundedUsize<MIN, { i32::MAX as usize }>>> {
+				if let Some(value) = expr {
+					Ok(Some(push_frame(
+						loc,
+						|| format!("slice {}", desc),
+						|| Ok(evaluate(context.clone(), value)?.try_into()?),
+					)?))
+				} else {
+					Ok(None)
+				}
 			}
 
-			let start = parse_num(&context, desc.start.as_ref(), "start")?;
-			let end = parse_num(&context, desc.end.as_ref(), "end")?;
-			let step = parse_num(&context, desc.step.as_ref(), "step")?;
+			let start = parse_idx(loc, &context, &desc.start, "start")?;
+			let end = parse_idx(loc, &context, &desc.end, "end")?;
+			let step = parse_idx(loc, &context, &desc.step, "step")?;
 
 			std_slice(indexable.into_indexable()?, start, end, step)?
 		}
modifiedcrates/jrsonnet-evaluator/src/typed/conversions.rsdiffbeforeafterboth
before · crates/jrsonnet-evaluator/src/typed/conversions.rs
1use std::{2	convert::{TryFrom, TryInto},3	rc::Rc,4};56use gcmodule::Cc;7use jrsonnet_interner::IStr;8pub use jrsonnet_macros::Typed;9use jrsonnet_types::{ComplexValType, ValType};1011use crate::{12	error::{Error::*, LocError, Result},13	throw,14	typed::CheckType,15	ArrValue, FuncDesc, FuncVal, IndexableVal, ObjValue, ObjValueBuilder, Val,16};1718pub trait TypedObj: Typed {19	fn serialize(self, out: &mut ObjValueBuilder) -> Result<()>;20	fn parse(obj: &ObjValue) -> Result<Self>;21	fn into_object(self) -> Result<ObjValue> {22		let mut builder = ObjValueBuilder::new();23		self.serialize(&mut builder)?;24		Ok(builder.build())25	}26}2728pub trait Typed: TryFrom<Val, Error = LocError> + TryInto<Val, Error = LocError> {29	const TYPE: &'static ComplexValType;30}3132macro_rules! impl_int {33	($($ty:ty)*) => {$(34		impl Typed for $ty {35			const TYPE: &'static ComplexValType =36				&ComplexValType::BoundedNumber(Some(Self::MIN as f64), Some(Self::MAX as f64));37		}38		impl TryFrom<Val> for $ty {39			type Error = LocError;4041			fn try_from(value: Val) -> Result<Self> {42				<Self as Typed>::TYPE.check(&value)?;43				match value {44					Val::Num(n) => {45						if n.trunc() != n {46							throw!(RuntimeError(47								format!(48									"cannot convert number with fractional part to {}",49									stringify!($ty)50								)51								.into()52							))53						}54						Ok(n as Self)55					}56					_ => unreachable!(),57				}58			}59		}60		impl TryFrom<$ty> for Val {61			type Error = LocError;6263			fn try_from(value: $ty) -> Result<Self> {64				Ok(Self::Num(value as f64))65			}66		}67	)*};68}6970impl_int!(i8 u8 i16 u16 i32 u32);7172impl Typed for f64 {73	const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Num);74}75impl TryFrom<Val> for f64 {76	type Error = LocError;7778	fn try_from(value: Val) -> Result<Self> {79		<Self as Typed>::TYPE.check(&value)?;80		match value {81			Val::Num(n) => Ok(n),82			_ => unreachable!(),83		}84	}85}86impl TryFrom<f64> for Val {87	type Error = LocError;8889	fn try_from(value: f64) -> Result<Self> {90		Ok(Self::Num(value))91	}92}9394pub struct PositiveF64(pub f64);95impl Typed for PositiveF64 {96	const TYPE: &'static ComplexValType = &ComplexValType::BoundedNumber(Some(0.0), None);97}98impl TryFrom<Val> for PositiveF64 {99	type Error = LocError;100101	fn try_from(value: Val) -> Result<Self> {102		<Self as Typed>::TYPE.check(&value)?;103		match value {104			Val::Num(n) => Ok(Self(n)),105			_ => unreachable!(),106		}107	}108}109impl TryFrom<PositiveF64> for Val {110	type Error = LocError;111112	fn try_from(value: PositiveF64) -> Result<Self> {113		Ok(Self::Num(value.0))114	}115}116117impl Typed for usize {118	// It is possible to store 54 bits of precision in f64, but leaving u32::MAX here for compatibility119	const TYPE: &'static ComplexValType =120		&ComplexValType::BoundedNumber(Some(0.0), Some(4294967295.0));121}122impl TryFrom<Val> for usize {123	type Error = LocError;124125	fn try_from(value: Val) -> Result<Self> {126		<Self as Typed>::TYPE.check(&value)?;127		match value {128			Val::Num(n) => {129				if n.trunc() != n {130					throw!(RuntimeError(131						"cannot convert number with fractional part to usize".into()132					))133				}134				Ok(n as Self)135			}136			_ => unreachable!(),137		}138	}139}140impl TryFrom<usize> for Val {141	type Error = LocError;142143	fn try_from(value: usize) -> Result<Self> {144		if value > u32::MAX as usize {145			throw!(RuntimeError("number is too large".into()))146		}147		Ok(Self::Num(value as f64))148	}149}150151impl Typed for IStr {152	const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Str);153}154impl TryFrom<Val> for IStr {155	type Error = LocError;156157	fn try_from(value: Val) -> Result<Self> {158		<Self as Typed>::TYPE.check(&value)?;159		match value {160			Val::Str(s) => Ok(s),161			_ => unreachable!(),162		}163	}164}165impl TryFrom<IStr> for Val {166	type Error = LocError;167168	fn try_from(value: IStr) -> Result<Self> {169		Ok(Self::Str(value))170	}171}172173impl Typed for String {174	const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Str);175}176impl TryFrom<Val> for String {177	type Error = LocError;178179	fn try_from(value: Val) -> Result<Self> {180		<Self as Typed>::TYPE.check(&value)?;181		match value {182			Val::Str(s) => Ok(s.to_string()),183			_ => unreachable!(),184		}185	}186}187impl TryFrom<String> for Val {188	type Error = LocError;189190	fn try_from(value: String) -> Result<Self> {191		Ok(Self::Str(value.into()))192	}193}194195impl Typed for char {196	const TYPE: &'static ComplexValType = &ComplexValType::Char;197}198impl TryFrom<Val> for char {199	type Error = LocError;200201	fn try_from(value: Val) -> Result<Self> {202		<Self as Typed>::TYPE.check(&value)?;203		match value {204			Val::Str(s) => Ok(s.chars().next().unwrap()),205			_ => unreachable!(),206		}207	}208}209impl TryFrom<char> for Val {210	type Error = LocError;211212	fn try_from(value: char) -> Result<Self> {213		Ok(Self::Str(value.to_string().into()))214	}215}216217impl<T> Typed for Vec<T>218where219	T: Typed,220	T: TryFrom<Val, Error = LocError>,221	T: TryInto<Val, Error = LocError>,222{223	const TYPE: &'static ComplexValType = &ComplexValType::ArrayRef(T::TYPE);224}225impl<T> TryFrom<Val> for Vec<T>226where227	T: Typed,228	T: TryFrom<Val, Error = LocError>,229	T: TryInto<Val, Error = LocError>,230{231	type Error = LocError;232233	fn try_from(value: Val) -> Result<Self> {234		<Self as Typed>::TYPE.check(&value)?;235		match value {236			Val::Arr(a) => {237				let mut o = Self::with_capacity(a.len());238				for i in a.iter() {239					o.push(T::try_from(i?)?);240				}241				Ok(o)242			}243			_ => unreachable!(),244		}245	}246}247impl<T> TryFrom<Vec<T>> for Val248where249	T: Typed,250	T: TryFrom<Self, Error = LocError>,251	T: TryInto<Self, Error = LocError>,252{253	type Error = LocError;254255	fn try_from(value: Vec<T>) -> Result<Self> {256		let mut o = Vec::with_capacity(value.len());257		for i in value {258			o.push(i.try_into()?);259		}260		Ok(Self::Arr(o.into()))261	}262}263264/// To be used in Vec<Any>265/// Regular Val can't be used here, because it has wrong TryFrom::Error type266#[derive(Clone)]267pub struct Any(pub Val);268269impl Typed for Any {270	const TYPE: &'static ComplexValType = &ComplexValType::Any;271}272impl TryFrom<Val> for Any {273	type Error = LocError;274275	fn try_from(value: Val) -> Result<Self> {276		Ok(Self(value))277	}278}279impl TryFrom<Any> for Val {280	type Error = LocError;281282	fn try_from(value: Any) -> Result<Self> {283		Ok(value.0)284	}285}286287/// Specialization, provides faster TryFrom<VecVal> for Val288pub struct VecVal(pub Cc<Vec<Val>>);289290impl Typed for VecVal {291	const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Arr);292}293impl TryFrom<Val> for VecVal {294	type Error = LocError;295296	fn try_from(value: Val) -> Result<Self> {297		<Self as Typed>::TYPE.check(&value)?;298		match value {299			Val::Arr(a) => Ok(Self(a.evaluated()?)),300			_ => unreachable!(),301		}302	}303}304impl TryFrom<VecVal> for Val {305	type Error = LocError;306307	fn try_from(value: VecVal) -> Result<Self> {308		Ok(Self::Arr(ArrValue::Eager(value.0)))309	}310}311312/// Specialization313pub struct Bytes(pub Rc<[u8]>);314315impl Typed for Bytes {316	const TYPE: &'static ComplexValType =317		&ComplexValType::ArrayRef(&ComplexValType::BoundedNumber(Some(0.0), Some(255.0)));318}319impl TryFrom<Val> for Bytes {320	type Error = LocError;321322	fn try_from(value: Val) -> Result<Self> {323		match value {324			Val::Arr(ArrValue::Bytes(bytes)) => Ok(Self(bytes)),325			_ => {326				<Self as Typed>::TYPE.check(&value)?;327				match value {328					Val::Arr(a) => {329						let mut out = Vec::with_capacity(a.len());330						for e in a.iter() {331							let r = e?;332							out.push(u8::try_from(r)?);333						}334						Ok(Self(out.into()))335					}336					_ => unreachable!(),337				}338			}339		}340	}341}342impl TryFrom<Bytes> for Val {343	type Error = LocError;344345	fn try_from(value: Bytes) -> Result<Self> {346		Ok(Self::Arr(ArrValue::Bytes(value.0)))347	}348}349350pub struct M1;351impl Typed for M1 {352	const TYPE: &'static ComplexValType = &ComplexValType::BoundedNumber(Some(-1.0), Some(-1.0));353}354impl TryFrom<Val> for M1 {355	type Error = LocError;356357	fn try_from(value: Val) -> Result<Self> {358		<Self as Typed>::TYPE.check(&value)?;359		Ok(Self)360	}361}362impl TryFrom<M1> for Val {363	type Error = LocError;364365	fn try_from(_: M1) -> Result<Self> {366		Ok(Self::Num(-1.0))367	}368}369370macro_rules! decl_either {371	($($name: ident, $($id: ident)*);*) => {$(372		pub enum $name<$($id),*> {373			$($id($id)),*374		}375		impl<$($id),*> Typed for $name<$($id),*>376		where377			$($id: Typed,)*378		{379			const TYPE: &'static ComplexValType = &ComplexValType::UnionRef(&[$($id::TYPE),*]);380		}381		impl<$($id),*> TryFrom<Val> for $name<$($id),*>382		where383			$($id: Typed,)*384		{385			type Error = LocError;386387			fn try_from(value: Val) -> Result<Self> {388				$(389					if $id::TYPE.check(&value).is_ok() {390						$id::try_from(value).map(Self::$id)391					} else392				)* {393					<Self as Typed>::TYPE.check(&value)?;394					unreachable!()395				}396			}397		}398		impl<$($id),*> TryFrom<$name<$($id),*>> for Val399		where400			$($id: Typed,)*401		{402			type Error = LocError;403			fn try_from(value: $name<$($id),*>) -> Result<Self> {404				match value {$(405					$name::$id(v) => v.try_into()406				),*}407			}408		}409	)*}410}411decl_either!(412	Either1, A;413	Either2, A B;414	Either3, A B C;415	Either4, A B C D;416	Either5, A B C D E;417	Either6, A B C D E F;418	Either7, A B C D E F G419);420#[macro_export]421macro_rules! Either {422	($a:ty) => {Either1<$a>};423	($a:ty, $b:ty) => {Either2<$a, $b>};424	($a:ty, $b:ty, $c:ty) => {Either3<$a, $b, $c>};425	($a:ty, $b:ty, $c:ty, $d:ty) => {Either4<$a, $b, $c, $d>};426	($a:ty, $b:ty, $c:ty, $d:ty, $e:ty) => {Either5<$a, $b, $c, $d, $e>};427	($a:ty, $b:ty, $c:ty, $d:ty, $e:ty, $f:ty) => {Either6<$a, $b, $c, $d, $e, $f>};428	($a:ty, $b:ty, $c:ty, $d:ty, $e:ty, $f:ty, $g:ty) => {Either7<$a, $b, $c, $d, $e, $f, $g>};429}430431pub type MyType = Either![u32, f64, String];432433impl Typed for ArrValue {434	const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Arr);435}436impl TryFrom<Val> for ArrValue {437	type Error = LocError;438439	fn try_from(value: Val) -> Result<Self> {440		<Self as Typed>::TYPE.check(&value)?;441		match value {442			Val::Arr(a) => Ok(a),443			_ => unreachable!(),444		}445	}446}447impl TryFrom<ArrValue> for Val {448	type Error = LocError;449450	fn try_from(value: ArrValue) -> Result<Self> {451		Ok(Self::Arr(value))452	}453}454455impl Typed for FuncVal {456	const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Func);457}458impl TryFrom<Val> for FuncVal {459	type Error = LocError;460461	fn try_from(value: Val) -> Result<Self> {462		<Self as Typed>::TYPE.check(&value)?;463		match value {464			Val::Func(a) => Ok(a),465			_ => unreachable!(),466		}467	}468}469impl TryFrom<FuncVal> for Val {470	type Error = LocError;471472	fn try_from(value: FuncVal) -> Result<Self> {473		Ok(Self::Func(value))474	}475}476477impl Typed for Cc<FuncDesc> {478	const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Func);479}480impl TryFrom<Val> for Cc<FuncDesc> {481	type Error = LocError;482483	fn try_from(value: Val) -> Result<Self, Self::Error> {484		<Self as Typed>::TYPE.check(&value)?;485		match value {486			Val::Func(FuncVal::Normal(desc)) => Ok(desc),487			Val::Func(_) => throw!(RuntimeError("expected normal function, not builtin".into())),488			_ => unreachable!(),489		}490	}491}492impl TryFrom<Cc<FuncDesc>> for Val {493	type Error = LocError;494495	fn try_from(value: Cc<FuncDesc>) -> Result<Self, Self::Error> {496		Ok(Self::Func(FuncVal::Normal(value)))497	}498}499500impl Typed for ObjValue {501	const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Obj);502}503impl TryFrom<Val> for ObjValue {504	type Error = LocError;505506	fn try_from(value: Val) -> Result<Self> {507		<Self as Typed>::TYPE.check(&value)?;508		match value {509			Val::Obj(a) => Ok(a),510			_ => unreachable!(),511		}512	}513}514impl TryFrom<ObjValue> for Val {515	type Error = LocError;516517	fn try_from(value: ObjValue) -> Result<Self> {518		Ok(Self::Obj(value))519	}520}521522impl Typed for bool {523	const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Bool);524}525impl TryFrom<Val> for bool {526	type Error = LocError;527528	fn try_from(value: Val) -> Result<Self> {529		<Self as Typed>::TYPE.check(&value)?;530		match value {531			Val::Bool(a) => Ok(a),532			_ => unreachable!(),533		}534	}535}536impl TryFrom<bool> for Val {537	type Error = LocError;538539	fn try_from(value: bool) -> Result<Self> {540		Ok(Self::Bool(value))541	}542}543544impl Typed for IndexableVal {545	const TYPE: &'static ComplexValType = &ComplexValType::UnionRef(&[546		&ComplexValType::Simple(ValType::Arr),547		&ComplexValType::Simple(ValType::Str),548	]);549}550impl TryFrom<Val> for IndexableVal {551	type Error = LocError;552553	fn try_from(value: Val) -> Result<Self> {554		<Self as Typed>::TYPE.check(&value)?;555		value.into_indexable()556	}557}558impl TryFrom<IndexableVal> for Val {559	type Error = LocError;560561	fn try_from(value: IndexableVal) -> Result<Self> {562		match value {563			IndexableVal::Str(s) => Ok(Self::Str(s)),564			IndexableVal::Arr(a) => Ok(Self::Arr(a)),565		}566	}567}568569pub struct Null;570impl Typed for Null {571	const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Null);572}573impl TryFrom<Val> for Null {574	type Error = LocError;575576	fn try_from(value: Val) -> Result<Self> {577		<Self as Typed>::TYPE.check(&value)?;578		Ok(Self)579	}580}581impl TryFrom<Null> for Val {582	type Error = LocError;583584	fn try_from(_: Null) -> Result<Self> {585		Ok(Self::Null)586	}587}
after · crates/jrsonnet-evaluator/src/typed/conversions.rs
1use std::{2	convert::{TryFrom, TryInto},3	ops::Deref,4	rc::Rc,5};67use gcmodule::Cc;8use jrsonnet_interner::IStr;9pub use jrsonnet_macros::Typed;10use jrsonnet_types::{ComplexValType, ValType};1112use crate::{13	error::{Error::*, LocError, Result},14	throw,15	typed::CheckType,16	val::{ArrValue, FuncDesc, FuncVal, IndexableVal},17	ObjValue, ObjValueBuilder, Val,18};1920pub trait TypedObj: Typed {21	fn serialize(self, out: &mut ObjValueBuilder) -> Result<()>;22	fn parse(obj: &ObjValue) -> Result<Self>;23	fn into_object(self) -> Result<ObjValue> {24		let mut builder = ObjValueBuilder::new();25		self.serialize(&mut builder)?;26		Ok(builder.build())27	}28}2930pub trait Typed: TryFrom<Val, Error = LocError> + TryInto<Val, Error = LocError> {31	const TYPE: &'static ComplexValType;32}3334macro_rules! impl_int {35	($($ty:ty)*) => {$(36		impl Typed for $ty {37			const TYPE: &'static ComplexValType =38				&ComplexValType::BoundedNumber(Some(Self::MIN as f64), Some(Self::MAX as f64));39		}40		impl TryFrom<Val> for $ty {41			type Error = LocError;4243			fn try_from(value: Val) -> Result<Self> {44				<Self as Typed>::TYPE.check(&value)?;45				match value {46					Val::Num(n) => {47						if n.trunc() != n {48							throw!(RuntimeError(49								format!(50									"cannot convert number with fractional part to {}",51									stringify!($ty)52								)53								.into()54							))55						}56						Ok(n as Self)57					}58					_ => unreachable!(),59				}60			}61		}62		impl TryFrom<$ty> for Val {63			type Error = LocError;6465			fn try_from(value: $ty) -> Result<Self> {66				Ok(Self::Num(value as f64))67			}68		}69	)*};70}7172impl_int!(i8 u8 i16 u16 i32 u32);7374macro_rules! impl_bounded_int {75	($($name:ident = $ty:ty)*) => {$(76		#[derive(Clone, Copy)]77		pub struct $name<const MIN: $ty, const MAX: $ty>($ty);78		impl<const MIN: $ty, const MAX: $ty> $name<MIN, MAX> {79			pub const fn new(value: $ty) -> Option<$name<MIN, MAX>> {80				if value >= MIN && value <= MAX {81					Some(Self(value))82				} else {83					None84				}85			}86			pub const fn value(self) -> $ty {87				self.088			}89		}90		impl<const MIN: $ty, const MAX: $ty> Deref for $name<MIN, MAX> {91			type Target = $ty;92			fn deref(&self) -> &Self::Target {93				&self.094			}95		}9697		impl<const MIN: $ty, const MAX: $ty> Typed for $name<MIN, MAX> {98			const TYPE: &'static ComplexValType =99				&ComplexValType::BoundedNumber(100					Some(MIN as f64),101					Some(MAX as f64),102				);103		}104		impl<const MIN: $ty, const MAX: $ty> TryFrom<Val> for $name<MIN, MAX> {105			type Error = LocError;106107			fn try_from(value: Val) -> Result<Self> {108				<Self as Typed>::TYPE.check(&value)?;109				match value {110					Val::Num(n) => {111						if n.trunc() != n {112							throw!(RuntimeError(113								format!(114									"cannot convert number with fractional part to {}",115									stringify!($ty)116								)117								.into()118							))119						}120						Ok(Self(n as $ty))121					}122					_ => unreachable!(),123				}124			}125		}126		impl<const MIN: $ty, const MAX: $ty> TryFrom<$name<MIN, MAX>> for Val {127			type Error = LocError;128129			fn try_from(value: $name<MIN, MAX>) -> Result<Self> {130				Ok(Self::Num(value.0 as f64))131			}132		}133	)*};134}135136impl_bounded_int!(137	BoundedI8 = i8138	BoundedI16 = i16139	BoundedI32 = i32140	BoundedI64 = i64141	BoundedUsize = usize142);143144impl Typed for f64 {145	const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Num);146}147impl TryFrom<Val> for f64 {148	type Error = LocError;149150	fn try_from(value: Val) -> Result<Self> {151		<Self as Typed>::TYPE.check(&value)?;152		match value {153			Val::Num(n) => Ok(n),154			_ => unreachable!(),155		}156	}157}158impl TryFrom<f64> for Val {159	type Error = LocError;160161	fn try_from(value: f64) -> Result<Self> {162		Ok(Self::Num(value))163	}164}165166pub struct PositiveF64(pub f64);167impl Typed for PositiveF64 {168	const TYPE: &'static ComplexValType = &ComplexValType::BoundedNumber(Some(0.0), None);169}170impl TryFrom<Val> for PositiveF64 {171	type Error = LocError;172173	fn try_from(value: Val) -> Result<Self> {174		<Self as Typed>::TYPE.check(&value)?;175		match value {176			Val::Num(n) => Ok(Self(n)),177			_ => unreachable!(),178		}179	}180}181impl TryFrom<PositiveF64> for Val {182	type Error = LocError;183184	fn try_from(value: PositiveF64) -> Result<Self> {185		Ok(Self::Num(value.0))186	}187}188189impl Typed for usize {190	// It is possible to store 54 bits of precision in f64, but leaving u32::MAX here for compatibility191	const TYPE: &'static ComplexValType =192		&ComplexValType::BoundedNumber(Some(0.0), Some(4294967295.0));193}194impl TryFrom<Val> for usize {195	type Error = LocError;196197	fn try_from(value: Val) -> Result<Self> {198		<Self as Typed>::TYPE.check(&value)?;199		match value {200			Val::Num(n) => {201				if n.trunc() != n {202					throw!(RuntimeError(203						"cannot convert number with fractional part to usize".into()204					))205				}206				Ok(n as Self)207			}208			_ => unreachable!(),209		}210	}211}212impl TryFrom<usize> for Val {213	type Error = LocError;214215	fn try_from(value: usize) -> Result<Self> {216		if value > u32::MAX as usize {217			throw!(RuntimeError("number is too large".into()))218		}219		Ok(Self::Num(value as f64))220	}221}222223impl Typed for IStr {224	const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Str);225}226impl TryFrom<Val> for IStr {227	type Error = LocError;228229	fn try_from(value: Val) -> Result<Self> {230		<Self as Typed>::TYPE.check(&value)?;231		match value {232			Val::Str(s) => Ok(s),233			_ => unreachable!(),234		}235	}236}237impl TryFrom<IStr> for Val {238	type Error = LocError;239240	fn try_from(value: IStr) -> Result<Self> {241		Ok(Self::Str(value))242	}243}244245impl Typed for String {246	const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Str);247}248impl TryFrom<Val> for String {249	type Error = LocError;250251	fn try_from(value: Val) -> Result<Self> {252		<Self as Typed>::TYPE.check(&value)?;253		match value {254			Val::Str(s) => Ok(s.to_string()),255			_ => unreachable!(),256		}257	}258}259impl TryFrom<String> for Val {260	type Error = LocError;261262	fn try_from(value: String) -> Result<Self> {263		Ok(Self::Str(value.into()))264	}265}266267impl Typed for char {268	const TYPE: &'static ComplexValType = &ComplexValType::Char;269}270impl TryFrom<Val> for char {271	type Error = LocError;272273	fn try_from(value: Val) -> Result<Self> {274		<Self as Typed>::TYPE.check(&value)?;275		match value {276			Val::Str(s) => Ok(s.chars().next().unwrap()),277			_ => unreachable!(),278		}279	}280}281impl TryFrom<char> for Val {282	type Error = LocError;283284	fn try_from(value: char) -> Result<Self> {285		Ok(Self::Str(value.to_string().into()))286	}287}288289impl<T> Typed for Vec<T>290where291	T: Typed,292	T: TryFrom<Val, Error = LocError>,293	T: TryInto<Val, Error = LocError>,294{295	const TYPE: &'static ComplexValType = &ComplexValType::ArrayRef(T::TYPE);296}297impl<T> TryFrom<Val> for Vec<T>298where299	T: Typed,300	T: TryFrom<Val, Error = LocError>,301	T: TryInto<Val, Error = LocError>,302{303	type Error = LocError;304305	fn try_from(value: Val) -> Result<Self> {306		<Self as Typed>::TYPE.check(&value)?;307		match value {308			Val::Arr(a) => {309				let mut o = Self::with_capacity(a.len());310				for i in a.iter() {311					o.push(T::try_from(i?)?);312				}313				Ok(o)314			}315			_ => unreachable!(),316		}317	}318}319impl<T> TryFrom<Vec<T>> for Val320where321	T: Typed,322	T: TryFrom<Self, Error = LocError>,323	T: TryInto<Self, Error = LocError>,324{325	type Error = LocError;326327	fn try_from(value: Vec<T>) -> Result<Self> {328		let mut o = Vec::with_capacity(value.len());329		for i in value {330			o.push(i.try_into()?);331		}332		Ok(Self::Arr(o.into()))333	}334}335336/// To be used in Vec<Any>337/// Regular Val can't be used here, because it has wrong TryFrom::Error type338#[derive(Clone)]339pub struct Any(pub Val);340341impl Typed for Any {342	const TYPE: &'static ComplexValType = &ComplexValType::Any;343}344impl TryFrom<Val> for Any {345	type Error = LocError;346347	fn try_from(value: Val) -> Result<Self> {348		Ok(Self(value))349	}350}351impl TryFrom<Any> for Val {352	type Error = LocError;353354	fn try_from(value: Any) -> Result<Self> {355		Ok(value.0)356	}357}358359/// Specialization, provides faster TryFrom<VecVal> for Val360pub struct VecVal(pub Cc<Vec<Val>>);361362impl Typed for VecVal {363	const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Arr);364}365impl TryFrom<Val> for VecVal {366	type Error = LocError;367368	fn try_from(value: Val) -> Result<Self> {369		<Self as Typed>::TYPE.check(&value)?;370		match value {371			Val::Arr(a) => Ok(Self(a.evaluated()?)),372			_ => unreachable!(),373		}374	}375}376impl TryFrom<VecVal> for Val {377	type Error = LocError;378379	fn try_from(value: VecVal) -> Result<Self> {380		Ok(Self::Arr(ArrValue::Eager(value.0)))381	}382}383384/// Specialization385pub struct Bytes(pub Rc<[u8]>);386387impl Typed for Bytes {388	const TYPE: &'static ComplexValType =389		&ComplexValType::ArrayRef(&ComplexValType::BoundedNumber(Some(0.0), Some(255.0)));390}391impl TryFrom<Val> for Bytes {392	type Error = LocError;393394	fn try_from(value: Val) -> Result<Self> {395		match value {396			Val::Arr(ArrValue::Bytes(bytes)) => Ok(Self(bytes)),397			_ => {398				<Self as Typed>::TYPE.check(&value)?;399				match value {400					Val::Arr(a) => {401						let mut out = Vec::with_capacity(a.len());402						for e in a.iter() {403							let r = e?;404							out.push(u8::try_from(r)?);405						}406						Ok(Self(out.into()))407					}408					_ => unreachable!(),409				}410			}411		}412	}413}414impl TryFrom<Bytes> for Val {415	type Error = LocError;416417	fn try_from(value: Bytes) -> Result<Self> {418		Ok(Self::Arr(ArrValue::Bytes(value.0)))419	}420}421422pub struct M1;423impl Typed for M1 {424	const TYPE: &'static ComplexValType = &ComplexValType::BoundedNumber(Some(-1.0), Some(-1.0));425}426impl TryFrom<Val> for M1 {427	type Error = LocError;428429	fn try_from(value: Val) -> Result<Self> {430		<Self as Typed>::TYPE.check(&value)?;431		Ok(Self)432	}433}434impl TryFrom<M1> for Val {435	type Error = LocError;436437	fn try_from(_: M1) -> Result<Self> {438		Ok(Self::Num(-1.0))439	}440}441442macro_rules! decl_either {443	($($name: ident, $($id: ident)*);*) => {$(444		pub enum $name<$($id),*> {445			$($id($id)),*446		}447		impl<$($id),*> Typed for $name<$($id),*>448		where449			$($id: Typed,)*450		{451			const TYPE: &'static ComplexValType = &ComplexValType::UnionRef(&[$($id::TYPE),*]);452		}453		impl<$($id),*> TryFrom<Val> for $name<$($id),*>454		where455			$($id: Typed,)*456		{457			type Error = LocError;458459			fn try_from(value: Val) -> Result<Self> {460				$(461					if $id::TYPE.check(&value).is_ok() {462						$id::try_from(value).map(Self::$id)463					} else464				)* {465					<Self as Typed>::TYPE.check(&value)?;466					unreachable!()467				}468			}469		}470		impl<$($id),*> TryFrom<$name<$($id),*>> for Val471		where472			$($id: Typed,)*473		{474			type Error = LocError;475			fn try_from(value: $name<$($id),*>) -> Result<Self> {476				match value {$(477					$name::$id(v) => v.try_into()478				),*}479			}480		}481	)*}482}483decl_either!(484	Either1, A;485	Either2, A B;486	Either3, A B C;487	Either4, A B C D;488	Either5, A B C D E;489	Either6, A B C D E F;490	Either7, A B C D E F G491);492#[macro_export]493macro_rules! Either {494	($a:ty) => {Either1<$a>};495	($a:ty, $b:ty) => {Either2<$a, $b>};496	($a:ty, $b:ty, $c:ty) => {Either3<$a, $b, $c>};497	($a:ty, $b:ty, $c:ty, $d:ty) => {Either4<$a, $b, $c, $d>};498	($a:ty, $b:ty, $c:ty, $d:ty, $e:ty) => {Either5<$a, $b, $c, $d, $e>};499	($a:ty, $b:ty, $c:ty, $d:ty, $e:ty, $f:ty) => {Either6<$a, $b, $c, $d, $e, $f>};500	($a:ty, $b:ty, $c:ty, $d:ty, $e:ty, $f:ty, $g:ty) => {Either7<$a, $b, $c, $d, $e, $f, $g>};501}502503pub type MyType = Either![u32, f64, String];504505impl Typed for ArrValue {506	const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Arr);507}508impl TryFrom<Val> for ArrValue {509	type Error = LocError;510511	fn try_from(value: Val) -> Result<Self> {512		<Self as Typed>::TYPE.check(&value)?;513		match value {514			Val::Arr(a) => Ok(a),515			_ => unreachable!(),516		}517	}518}519impl TryFrom<ArrValue> for Val {520	type Error = LocError;521522	fn try_from(value: ArrValue) -> Result<Self> {523		Ok(Self::Arr(value))524	}525}526527impl Typed for FuncVal {528	const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Func);529}530impl TryFrom<Val> for FuncVal {531	type Error = LocError;532533	fn try_from(value: Val) -> Result<Self> {534		<Self as Typed>::TYPE.check(&value)?;535		match value {536			Val::Func(a) => Ok(a),537			_ => unreachable!(),538		}539	}540}541impl TryFrom<FuncVal> for Val {542	type Error = LocError;543544	fn try_from(value: FuncVal) -> Result<Self> {545		Ok(Self::Func(value))546	}547}548549impl Typed for Cc<FuncDesc> {550	const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Func);551}552impl TryFrom<Val> for Cc<FuncDesc> {553	type Error = LocError;554555	fn try_from(value: Val) -> Result<Self, Self::Error> {556		<Self as Typed>::TYPE.check(&value)?;557		match value {558			Val::Func(FuncVal::Normal(desc)) => Ok(desc),559			Val::Func(_) => throw!(RuntimeError("expected normal function, not builtin".into())),560			_ => unreachable!(),561		}562	}563}564impl TryFrom<Cc<FuncDesc>> for Val {565	type Error = LocError;566567	fn try_from(value: Cc<FuncDesc>) -> Result<Self, Self::Error> {568		Ok(Self::Func(FuncVal::Normal(value)))569	}570}571572impl Typed for ObjValue {573	const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Obj);574}575impl TryFrom<Val> for ObjValue {576	type Error = LocError;577578	fn try_from(value: Val) -> Result<Self> {579		<Self as Typed>::TYPE.check(&value)?;580		match value {581			Val::Obj(a) => Ok(a),582			_ => unreachable!(),583		}584	}585}586impl TryFrom<ObjValue> for Val {587	type Error = LocError;588589	fn try_from(value: ObjValue) -> Result<Self> {590		Ok(Self::Obj(value))591	}592}593594impl Typed for bool {595	const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Bool);596}597impl TryFrom<Val> for bool {598	type Error = LocError;599600	fn try_from(value: Val) -> Result<Self> {601		<Self as Typed>::TYPE.check(&value)?;602		match value {603			Val::Bool(a) => Ok(a),604			_ => unreachable!(),605		}606	}607}608impl TryFrom<bool> for Val {609	type Error = LocError;610611	fn try_from(value: bool) -> Result<Self> {612		Ok(Self::Bool(value))613	}614}615616impl Typed for IndexableVal {617	const TYPE: &'static ComplexValType = &ComplexValType::UnionRef(&[618		&ComplexValType::Simple(ValType::Arr),619		&ComplexValType::Simple(ValType::Str),620	]);621}622impl TryFrom<Val> for IndexableVal {623	type Error = LocError;624625	fn try_from(value: Val) -> Result<Self> {626		<Self as Typed>::TYPE.check(&value)?;627		value.into_indexable()628	}629}630impl TryFrom<IndexableVal> for Val {631	type Error = LocError;632633	fn try_from(value: IndexableVal) -> Result<Self> {634		match value {635			IndexableVal::Str(s) => Ok(Self::Str(s)),636			IndexableVal::Arr(a) => Ok(Self::Arr(a)),637		}638	}639}640641pub struct Null;642impl Typed for Null {643	const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Null);644}645impl TryFrom<Val> for Null {646	type Error = LocError;647648	fn try_from(value: Val) -> Result<Self> {649		<Self as Typed>::TYPE.check(&value)?;650		Ok(Self)651	}652}653impl TryFrom<Null> for Val {654	type Error = LocError;655656	fn try_from(_: Null) -> Result<Self> {657		Ok(Self::Null)658	}659}
modifiedcrates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/val.rs
+++ b/crates/jrsonnet-evaluator/src/val.rs
@@ -172,6 +172,37 @@
 }
 
 #[derive(Debug, Clone, Trace)]
+pub struct Slice {
+	pub(crate) inner: ArrValue,
+	pub(crate) from: u32,
+	pub(crate) to: u32,
+	pub(crate) step: u32,
+}
+impl Slice {
+	fn from(&self) -> usize {
+		self.from as usize
+	}
+	fn to(&self) -> usize {
+		self.to as usize
+	}
+	fn step(&self) -> usize {
+		self.step as usize
+	}
+	fn len(&self) -> usize {
+		// TODO: use div_ceil
+		let diff = self.to() - self.from();
+		let rem = diff % self.step();
+		let div = diff / self.step();
+
+		if rem != 0 {
+			div + 1
+		} else {
+			div
+		}
+	}
+}
+
+#[derive(Debug, Clone, Trace)]
 #[force_tracking]
 pub enum ArrValue {
 	Bytes(#[skip_trace] Rc<[u8]>),
@@ -179,6 +210,7 @@
 	Eager(Cc<Vec<Val>>),
 	Extended(Box<(Self, Self)>),
 	Range(i32, i32),
+	Slice(Box<Slice>),
 	Reversed(Box<Self>),
 }
 impl ArrValue {
@@ -190,6 +222,22 @@
 		Self::Range(a, b)
 	}
 
+	pub fn slice(self, from: Option<usize>, to: Option<usize>, step: Option<usize>) -> Self {
+		let len = self.len();
+		let from = from.unwrap_or(0);
+		let to = to.unwrap_or(len).min(len);
+		let step = step.unwrap_or(1);
+		assert!(from < to);
+		assert!(step > 0);
+
+		Self::Slice(Box::new(Slice {
+			inner: self,
+			from: from as u32,
+			to: to as u32,
+			step: step as u32,
+		}))
+	}
+
 	pub fn len(&self) -> usize {
 		match self {
 			Self::Bytes(i) => i.len(),
@@ -198,6 +246,7 @@
 			Self::Extended(v) => v.0.len() + v.1.len(),
 			Self::Range(a, b) => a.abs_diff(*b) as usize,
 			Self::Reversed(i) => i.len(),
+			Self::Slice(s) => s.len(),
 		}
 	}
 
@@ -239,6 +288,13 @@
 				}
 				v.get(len - index - 1)
 			}
+			Self::Slice(s) => {
+				let index = s.from() + index * s.step();
+				if index >= s.to() {
+					return Ok(None);
+				}
+				s.inner.get(index as usize)
+			}
 		}
 	}
 
@@ -272,6 +328,13 @@
 				}
 				v.get_lazy(len - index - 1)
 			}
+			Self::Slice(s) => {
+				let index = s.from() + index * s.step();
+				if index >= s.to() {
+					return None;
+				}
+				s.inner.get_lazy(index as usize)
+			}
 		}
 	}
 
@@ -311,33 +374,43 @@
 				Cc::update_with(&mut r, |v| v.reverse());
 				r
 			}
+			Self::Slice(v) => {
+				let mut out = Vec::with_capacity(v.inner.len());
+				for v in v
+					.inner
+					.iter_lazy()
+					.skip(v.from())
+					.take(v.to() - v.from())
+					.step_by(v.step())
+				{
+					out.push(v.evaluate()?)
+				}
+				Cc::new(out)
+			}
 		})
 	}
 
 	pub fn iter(&self) -> impl DoubleEndedIterator<Item = Result<Val>> + '_ {
-		// if let Self::Reversed(v) = self {
-		// 	return v.iter().rev();
-		// }
-		let len = self.len();
-		(0..len).map(move |idx| match self {
+		(0..self.len()).map(move |idx| match self {
 			Self::Bytes(b) => Ok(Val::Num(b[idx] as f64)),
 			Self::Lazy(l) => l[idx].evaluate(),
 			Self::Eager(e) => Ok(e[idx].clone()),
 			Self::Extended(_) => self.get(idx).map(|e| e.unwrap()),
 			Self::Range(..) => self.get(idx).map(|e| e.unwrap()),
-			Self::Reversed(..) => self.get(len - idx - 1).map(|e| e.unwrap()),
+			Self::Reversed(..) => self.get(idx).map(|e| e.unwrap()),
+			Self::Slice(..) => self.get(idx).map(|e| e.unwrap()),
 		})
 	}
 
 	pub fn iter_lazy(&self) -> impl DoubleEndedIterator<Item = LazyVal> + '_ {
-		let len = self.len();
-		(0..len).map(move |idx| match self {
+		(0..self.len()).map(move |idx| match self {
 			Self::Bytes(b) => LazyVal::new_resolved(Val::Num(b[idx] as f64)),
 			Self::Lazy(l) => l[idx].clone(),
 			Self::Eager(e) => LazyVal::new_resolved(e[idx].clone()),
 			Self::Extended(_) => self.get_lazy(idx).unwrap(),
 			Self::Range(..) => self.get_lazy(idx).unwrap(),
-			Self::Reversed(..) => self.get_lazy(len - idx - 1).unwrap(),
+			Self::Reversed(..) => self.get_lazy(idx).unwrap(),
+			Self::Slice(..) => self.get_lazy(idx).unwrap(),
 		})
 	}
 
@@ -459,17 +532,6 @@
 		}
 	}
 
-	pub fn try_cast_nullable_num(self, context: &'static str) -> Result<Option<f64>> {
-		Ok(match self {
-			Val::Null => None,
-			Val::Num(num) => Some(num),
-			_ => throw!(TypeMismatch(
-				context,
-				vec![ValType::Null, ValType::Num],
-				self.value_type()
-			)),
-		})
-	}
 	pub const fn value_type(&self) -> ValType {
 		match self {
 			Self::Str(..) => ValType::Str,