From fa16ccf5624ac069e1370b585f3f7a34683c5a9e Mon Sep 17 00:00:00 2001 From: Yaroslav Bolyukin Date: Mon, 27 Dec 2021 16:41:20 +0000 Subject: [PATCH] feat: varadic Either type --- --- a/crates/jrsonnet-evaluator/src/builtin/mod.rs +++ b/crates/jrsonnet-evaluator/src/builtin/mod.rs @@ -1,12 +1,14 @@ use crate::function::StaticBuiltin; -use crate::typed::{Any, Either, Null, PositiveF64, VecVal, M1}; -use crate::{self as jrsonnet_evaluator, ObjValue}; +use crate::typed::{Any, Null, PositiveF64, VecVal, M1}; +use crate::{self as jrsonnet_evaluator, Either, ObjValue}; use crate::{ builtin::manifest::{manifest_yaml_ex, ManifestYamlOptions}, equals, error::{Error::*, Result}, operator::evaluate_mod_op, - primitive_equals, push_frame, throw, with_state, ArrValue, Context, FuncVal, IndexableVal, Val, + primitive_equals, push_frame, throw, + typed::{Either2, Either4}, + with_state, ArrValue, Context, FuncVal, IndexableVal, Val, }; use format::{format_arr, format_obj}; use gcmodule::Cc; @@ -140,16 +142,17 @@ } #[jrsonnet_macros::builtin] -fn builtin_length(x: Either>>>) -> Result { +fn builtin_length(x: Either![IStr, VecVal, ObjValue, Cc]) -> Result { + use Either4::*; Ok(match x { - Either::Left(x) => x.len(), - Either::Right(Either::Left(x)) => x.0.len(), - Either::Right(Either::Right(Either::Left(x))) => x + A(x) => x.len(), + B(x) => x.0.len(), + C(x) => x .fields_visibility() .into_iter() .filter(|(_k, v)| *v) .count(), - Either::Right(Either::Right(Either::Right(f))) => f.args_len(), + D(f) => f.args_len(), }) } @@ -215,11 +218,11 @@ #[jrsonnet_macros::builtin] fn builtin_slice( indexable: IndexableVal, - index: Either, - end: Either, - step: Either, + index: Option, + end: Option, + step: Option, ) -> Result { - std_slice(indexable, index.left(), end.left(), step.left()).map(Any) + std_slice(indexable, index, end, step).map(Any) } #[jrsonnet_macros::builtin] @@ -243,11 +246,12 @@ } #[jrsonnet_macros::builtin] -fn builtin_mod(a: Either, b: Any) -> Result { +fn builtin_mod(a: Either![f64, IStr], b: Any) -> Result { + use Either2::*; Ok(Any(evaluate_mod_op( &match a { - Either::Left(v) => Val::Num(v), - Either::Right(s) => Val::Str(s), + A(v) => Val::Num(v), + B(s) => Val::Str(s), }, &b.0, )?)) @@ -481,10 +485,11 @@ } #[jrsonnet_macros::builtin] -fn builtin_base64(input: Either, IStr>) -> Result { +fn builtin_base64(input: Either![Vec, IStr]) -> Result { + use Either2::*; Ok(match input { - Either::Left(a) => base64::encode(a), - Either::Right(l) => base64::encode(l.bytes().collect::>()), + A(a) => base64::encode(a), + B(l) => base64::encode(l.bytes().collect::>()), }) } @@ -607,10 +612,11 @@ } #[jrsonnet_macros::builtin] -fn builtin_splitlimit(str: IStr, c: char, maxsplits: Either) -> Result { +fn builtin_splitlimit(str: IStr, c: char, maxsplits: Either![usize, M1]) -> Result { + use Either2::*; Ok(VecVal(match maxsplits { - Either::Left(n) => str.splitn(n + 1, c).map(|s| Val::Str(s.into())).collect(), - Either::Right(_) => str.split(c).map(|s| Val::Str(s.into())).collect(), + A(n) => str.splitn(n + 1, c).map(|s| Val::Str(s.into())).collect(), + B(_) => str.split(c).map(|s| Val::Str(s.into())).collect(), })) } --- a/crates/jrsonnet-evaluator/src/typed/conversions.rs +++ b/crates/jrsonnet-evaluator/src/typed/conversions.rs @@ -315,66 +315,68 @@ } } -pub enum Either { - 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 for $name<$($id),*> + where + $($id: Typed,)* + { + type Error = LocError; -impl Either { - 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 { + $( + if $id::TYPE.check(&value).is_ok() { + $id::try_from(value).map(Self::$id) + } else + )* { + ::TYPE.check(&value)?; + unreachable!() + } + } } - } - #[allow(clippy::missing_const_for_fn)] - pub fn left(self) -> Option { - 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 { + match value {$( + $name::$id(v) => v.try_into() + ),*} + } } - } + )*} } - -impl Typed for Either -where - A: Typed, - B: Typed, -{ - const TYPE: &'static ComplexValType = &ComplexValType::UnionRef(&[A::TYPE, B::TYPE]); -} -impl TryFrom for Either -where - A: Typed, - B: Typed, -{ - type Error = LocError; - - fn try_from(value: Val) -> Result { - 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 { - ::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 TryFrom> for Val -where - A: Typed, - B: Typed, -{ - type Error = LocError; - fn try_from(value: Either) -> Result { - 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); -- gitstuff