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

difftreelog

feat varadic Either type

Yaroslav Bolyukin2021-12-27parent: #8f3ed48.patch.diff
in: master

2 files changed

modifiedcrates/jrsonnet-evaluator/src/builtin/mod.rsdiffbeforeafterboth
1use crate::function::StaticBuiltin;1use crate::function::StaticBuiltin;
2use crate::typed::{Any, Either, Null, PositiveF64, VecVal, M1};2use crate::typed::{Any, Null, PositiveF64, VecVal, M1};
3use crate::{self as jrsonnet_evaluator, ObjValue};3use crate::{self as jrsonnet_evaluator, Either, ObjValue};
4use crate::{4use crate::{
5 builtin::manifest::{manifest_yaml_ex, ManifestYamlOptions},5 builtin::manifest::{manifest_yaml_ex, ManifestYamlOptions},
6 equals,6 equals,
7 error::{Error::*, Result},7 error::{Error::*, Result},
8 operator::evaluate_mod_op,8 operator::evaluate_mod_op,
9 primitive_equals, push_frame, throw, with_state, ArrValue, Context, FuncVal, IndexableVal, Val,9 primitive_equals, push_frame, throw,
10 typed::{Either2, Either4},
11 with_state, ArrValue, Context, FuncVal, IndexableVal, Val,
10};12};
11use format::{format_arr, format_obj};13use format::{format_arr, format_obj};
140}142}
141143
142#[jrsonnet_macros::builtin]144#[jrsonnet_macros::builtin]
143fn builtin_length(x: Either<IStr, Either<VecVal, Either<ObjValue, Cc<FuncVal>>>>) -> Result<usize> {145fn builtin_length(x: Either![IStr, VecVal, ObjValue, Cc<FuncVal>]) -> Result<usize> {
146 use Either4::*;
144 Ok(match x {147 Ok(match x {
145 Either::Left(x) => x.len(),148 A(x) => x.len(),
146 Either::Right(Either::Left(x)) => x.0.len(),149 B(x) => x.0.len(),
147 Either::Right(Either::Right(Either::Left(x))) => x150 C(x) => x
148 .fields_visibility()151 .fields_visibility()
149 .into_iter()152 .into_iter()
150 .filter(|(_k, v)| *v)153 .filter(|(_k, v)| *v)
151 .count(),154 .count(),
152 Either::Right(Either::Right(Either::Right(f))) => f.args_len(),155 D(f) => f.args_len(),
153 })156 })
154}157}
155158
215#[jrsonnet_macros::builtin]218#[jrsonnet_macros::builtin]
216fn builtin_slice(219fn builtin_slice(
217 indexable: IndexableVal,220 indexable: IndexableVal,
218 index: Either<usize, Null>,221 index: Option<usize>,
219 end: Either<usize, Null>,222 end: Option<usize>,
220 step: Either<usize, Null>,223 step: Option<usize>,
221) -> Result<Any> {224) -> Result<Any> {
222 std_slice(indexable, index.left(), end.left(), step.left()).map(Any)225 std_slice(indexable, index, end, step).map(Any)
223}226}
224227
225#[jrsonnet_macros::builtin]228#[jrsonnet_macros::builtin]
243}246}
244247
245#[jrsonnet_macros::builtin]248#[jrsonnet_macros::builtin]
246fn builtin_mod(a: Either<f64, IStr>, b: Any) -> Result<Any> {249fn builtin_mod(a: Either![f64, IStr], b: Any) -> Result<Any> {
250 use Either2::*;
247 Ok(Any(evaluate_mod_op(251 Ok(Any(evaluate_mod_op(
248 &match a {252 &match a {
249 Either::Left(v) => Val::Num(v),253 A(v) => Val::Num(v),
250 Either::Right(s) => Val::Str(s),254 B(s) => Val::Str(s),
251 },255 },
252 &b.0,256 &b.0,
253 )?))257 )?))
481}485}
482486
483#[jrsonnet_macros::builtin]487#[jrsonnet_macros::builtin]
484fn builtin_base64(input: Either<Vec<u8>, IStr>) -> Result<String> {488fn builtin_base64(input: Either![Vec<u8>, IStr]) -> Result<String> {
489 use Either2::*;
485 Ok(match input {490 Ok(match input {
486 Either::Left(a) => base64::encode(a),491 A(a) => base64::encode(a),
487 Either::Right(l) => base64::encode(l.bytes().collect::<Vec<_>>()),492 B(l) => base64::encode(l.bytes().collect::<Vec<_>>()),
488 })493 })
489}494}
490495
607}612}
608613
609#[jrsonnet_macros::builtin]614#[jrsonnet_macros::builtin]
610fn builtin_splitlimit(str: IStr, c: char, maxsplits: Either<usize, M1>) -> Result<VecVal> {615fn builtin_splitlimit(str: IStr, c: char, maxsplits: Either![usize, M1]) -> Result<VecVal> {
616 use Either2::*;
611 Ok(VecVal(match maxsplits {617 Ok(VecVal(match maxsplits {
612 Either::Left(n) => str.splitn(n + 1, c).map(|s| Val::Str(s.into())).collect(),618 A(n) => str.splitn(n + 1, c).map(|s| Val::Str(s.into())).collect(),
613 Either::Right(_) => str.split(c).map(|s| Val::Str(s.into())).collect(),619 B(_) => str.split(c).map(|s| Val::Str(s.into())).collect(),
614 }))620 }))
615}621}
616622
modifiedcrates/jrsonnet-evaluator/src/typed/conversions.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/typed/conversions.rs
+++ b/crates/jrsonnet-evaluator/src/typed/conversions.rs
@@ -315,66 +315,68 @@
 	}
 }
 
-pub enum Either<A, B> {
-	Left(A),
-	Right(B),
-}
+macro_rules! decl_either {
+	($($name: ident, $($id: ident)*);*) => {$(
+		pub enum $name<$($id),*> {
+			$($id($id)),*
+		}
+		impl<$($id),*> Typed for $name<$($id),*>
+		where
+			$($id: Typed,)*
+		{
+			const TYPE: &'static ComplexValType = &ComplexValType::UnionRef(&[$($id::TYPE),*]);
+		}
+		impl<$($id),*> TryFrom<Val> for $name<$($id),*>
+		where
+			$($id: Typed,)*
+		{
+			type Error = LocError;
 
-impl<A, B> Either<A, B> {
-	pub fn to_left(self, f: impl FnOnce(B) -> A) -> A {
-		match self {
-			Either::Left(l) => l,
-			Either::Right(r) => f(r),
+			fn try_from(value: Val) -> Result<Self> {
+				$(
+					if $id::TYPE.check(&value).is_ok() {
+						$id::try_from(value).map(Self::$id)
+					} else
+				)* {
+					<Self as Typed>::TYPE.check(&value)?;
+					unreachable!()
+				}
+			}
 		}
-	}
-	#[allow(clippy::missing_const_for_fn)]
-	pub fn left(self) -> Option<A> {
-		match self {
-			Either::Left(a) => Some(a),
-			Either::Right(_) => None,
+		impl<$($id),*> TryFrom<$name<$($id),*>> for Val
+		where
+			$($id: Typed,)*
+		{
+			type Error = LocError;
+			fn try_from(value: $name<$($id),*>) -> Result<Self> {
+				match value {$(
+					$name::$id(v) => v.try_into()
+				),*}
+			}
 		}
-	}
+	)*}
 }
-
-impl<A, B> Typed for Either<A, B>
-where
-	A: Typed,
-	B: Typed,
-{
-	const TYPE: &'static ComplexValType = &ComplexValType::UnionRef(&[A::TYPE, B::TYPE]);
-}
-impl<A, B> TryFrom<Val> for Either<A, B>
-where
-	A: Typed,
-	B: Typed,
-{
-	type Error = LocError;
-
-	fn try_from(value: Val) -> Result<Self> {
-		if A::TYPE.check(&value).is_ok() {
-			A::try_from(value).map(Self::Left)
-		} else if B::TYPE.check(&value).is_ok() {
-			B::try_from(value).map(Self::Right)
-		} else {
-			<Self as Typed>::TYPE.check(&value)?;
-			unreachable!()
-		}
-	}
+decl_either!(
+	Either1, A;
+	Either2, A B;
+	Either3, A B C;
+	Either4, A B C D;
+	Either5, A B C D E;
+	Either6, A B C D E F;
+	Either7, A B C D E F G
+);
+#[macro_export]
+macro_rules! Either {
+	($a:ty) => {Either1<$a>};
+	($a:ty, $b:ty) => {Either2<$a, $b>};
+	($a:ty, $b:ty, $c:ty) => {Either3<$a, $b, $c>};
+	($a:ty, $b:ty, $c:ty, $d:ty) => {Either4<$a, $b, $c, $d>};
+	($a:ty, $b:ty, $c:ty, $d:ty, $e:ty) => {Either5<$a, $b, $c, $d, $e>};
+	($a:ty, $b:ty, $c:ty, $d:ty, $e:ty, $f:ty) => {Either6<$a, $b, $c, $d, $e, $f>};
+	($a:ty, $b:ty, $c:ty, $d:ty, $e:ty, $f:ty, $g:ty) => {Either7<$a, $b, $c, $d, $e, $f, $g>};
 }
-impl<A, B> TryFrom<Either<A, B>> for Val
-where
-	A: Typed,
-	B: Typed,
-{
-	type Error = LocError;
 
-	fn try_from(value: Either<A, B>) -> Result<Self> {
-		match value {
-			Either::Left(a) => a.try_into(),
-			Either::Right(b) => b.try_into(),
-		}
-	}
-}
+pub type MyType = Either![u32, f64, String];
 
 impl Typed for ArrValue {
 	const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Arr);