use syn::parse_quote;
use tinc_cel::CelValue;
use super::{CompileError, CompiledExpr, Compiler, ConstantCompiledExpr, RuntimeCompiledExpr};
use crate::codegen::cel::types::CelType;
use crate::types::{ProtoModifiedValueType, ProtoType, ProtoValueType, ProtoWellKnownType};
impl CompiledExpr {
pub(crate) fn into_bool(self, compiler: &Compiler) -> CompiledExpr {
match &self {
CompiledExpr::Runtime(RuntimeCompiledExpr {
expr,
ty: CelType::Proto(ProtoType::Modified(ProtoModifiedValueType::OneOf(_))),
}) => CompiledExpr::Runtime(RuntimeCompiledExpr {
expr: parse_quote! { (#expr).is_some() },
ty: CelType::Proto(ProtoType::Value(ProtoValueType::Bool)),
}),
CompiledExpr::Runtime(RuntimeCompiledExpr {
expr,
ty: CelType::Proto(ProtoType::Modified(ProtoModifiedValueType::Optional(ty))),
}) => {
let value_to_bool = CompiledExpr::Runtime(RuntimeCompiledExpr {
expr: parse_quote! { ___to_bool_value },
ty: CelType::Proto(ProtoType::Value(ty.clone())),
})
.into_bool(compiler);
CompiledExpr::Runtime(RuntimeCompiledExpr {
expr: parse_quote! {
match #expr {
Some(___to_bool_value) => #value_to_bool,
None => false,
}
},
ty: CelType::Proto(ProtoType::Value(ProtoValueType::Bool)),
})
}
CompiledExpr::Runtime(RuntimeCompiledExpr {
ty: CelType::Proto(ProtoType::Value(ProtoValueType::Message { .. })),
..
}) => CompiledExpr::Constant(ConstantCompiledExpr {
value: tinc_cel::CelValue::Bool(true),
}),
CompiledExpr::Runtime(RuntimeCompiledExpr { expr, .. }) => CompiledExpr::Runtime(RuntimeCompiledExpr {
expr: parse_quote! {
::tinc::__private::cel::to_bool(#expr)
},
ty: CelType::Proto(ProtoType::Value(ProtoValueType::Bool)),
}),
CompiledExpr::Constant(ConstantCompiledExpr {
value: CelValue::Enum(cel_enum),
}) => CompiledExpr::Constant(ConstantCompiledExpr {
value: tinc_cel::CelValue::Bool(
compiler
.registry
.get_enum(&cel_enum.tag)
.is_some_and(|e| e.variants.values().any(|v| v.value == cel_enum.value)),
),
}),
CompiledExpr::Constant(ConstantCompiledExpr { value }) => CompiledExpr::Constant(ConstantCompiledExpr {
value: tinc_cel::CelValue::Bool(value.to_bool()),
}),
}
}
pub(crate) fn into_cel(self) -> Result<CompiledExpr, CompileError> {
match self {
CompiledExpr::Runtime(RuntimeCompiledExpr {
expr,
ty: ty @ CelType::CelValue,
}) => Ok(CompiledExpr::Runtime(RuntimeCompiledExpr { expr, ty })),
CompiledExpr::Runtime(RuntimeCompiledExpr {
expr,
ty:
CelType::Proto(ProtoType::Value(
ProtoValueType::Bool
| ProtoValueType::Bytes
| ProtoValueType::Double
| ProtoValueType::Float
| ProtoValueType::Int32
| ProtoValueType::Int64
| ProtoValueType::String
| ProtoValueType::UInt32
| ProtoValueType::UInt64
| ProtoValueType::WellKnown(
ProtoWellKnownType::Duration
| ProtoWellKnownType::Empty
| ProtoWellKnownType::ListValue
| ProtoWellKnownType::Struct
| ProtoWellKnownType::Timestamp
| ProtoWellKnownType::Value,
),
)),
}) => Ok(CompiledExpr::Runtime(RuntimeCompiledExpr {
expr: parse_quote! {
::tinc::__private::cel::CelValueConv::conv(#expr)
},
ty: CelType::CelValue,
})),
CompiledExpr::Runtime(RuntimeCompiledExpr {
expr,
ty: CelType::Proto(ProtoType::Modified(ProtoModifiedValueType::Map(key_ty, value_ty))),
}) => {
let key_to_cel = CompiledExpr::Runtime(RuntimeCompiledExpr {
expr: parse_quote!(key),
ty: CelType::Proto(ProtoType::Value(key_ty)),
})
.into_cel()?;
let value_to_cel = CompiledExpr::Runtime(RuntimeCompiledExpr {
expr: parse_quote!(value),
ty: CelType::Proto(ProtoType::Value(value_ty)),
})
.into_cel()?;
Ok(CompiledExpr::Runtime(RuntimeCompiledExpr {
expr: parse_quote! {
::tinc::__private::cel::CelValue::Map(
(#expr).into_iter().map(|(key, value)| {
(
#key_to_cel,
#value_to_cel,
)
}).collect()
)
},
ty: CelType::CelValue,
}))
}
CompiledExpr::Runtime(RuntimeCompiledExpr {
expr,
ty: CelType::Proto(ProtoType::Modified(ProtoModifiedValueType::Optional(some_ty))),
}) => {
let some_to_cel = CompiledExpr::Runtime(RuntimeCompiledExpr {
expr: parse_quote!(item),
ty: CelType::Proto(ProtoType::Value(some_ty)),
})
.into_cel()?;
Ok(CompiledExpr::Runtime(RuntimeCompiledExpr {
expr: parse_quote! {{
match (#expr) {
::core::option::Option::Some(item) => #some_to_cel,
::core::option::Option::None => ::tinc::__private::cel::CelValue::Null,
}
}},
ty: CelType::CelValue,
}))
}
CompiledExpr::Runtime(RuntimeCompiledExpr {
expr,
ty: CelType::Proto(ProtoType::Modified(ProtoModifiedValueType::Repeated(item_ty))),
}) => {
let item_to_cel = CompiledExpr::Runtime(RuntimeCompiledExpr {
expr: parse_quote!(item),
ty: CelType::Proto(ProtoType::Value(item_ty)),
})
.into_cel()?;
Ok(CompiledExpr::Runtime(RuntimeCompiledExpr {
expr: parse_quote! {
::tinc::__private::cel::CelValue::List((#expr).into_iter().map(|item| #item_to_cel).collect())
},
ty: CelType::CelValue,
}))
}
CompiledExpr::Runtime(RuntimeCompiledExpr {
expr,
ty: CelType::Proto(ProtoType::Value(ProtoValueType::Enum(path))),
}) => {
let path = path.as_ref();
Ok(CompiledExpr::Runtime(RuntimeCompiledExpr {
expr: parse_quote! {
::tinc::__private::cel::CelValue::cel_to_enum(
#expr,
#path,
)?
},
ty: CelType::CelValue,
}))
}
CompiledExpr::Runtime(RuntimeCompiledExpr {
ty: ty @ CelType::Proto(ProtoType::Modified(ProtoModifiedValueType::OneOf(_))),
..
}) => Err(CompileError::TypeConversion {
ty: Box::new(ty),
message: "oneofs cannot be converted into cel types".into(),
}),
CompiledExpr::Runtime(RuntimeCompiledExpr {
ty: ty @ CelType::Proto(ProtoType::Value(ProtoValueType::Message(_))),
..
}) => Err(CompileError::TypeConversion {
ty: Box::new(ty),
message: "message types cannot be converted into cel types".into(),
}),
CompiledExpr::Runtime(RuntimeCompiledExpr {
ty: ty @ CelType::Proto(ProtoType::Value(ProtoValueType::WellKnown(ProtoWellKnownType::Any))),
..
}) => Err(CompileError::TypeConversion {
ty: Box::new(ty),
message: "any cannot be converted into cel types".into(),
}),
CompiledExpr::Constant(c) => Ok(CompiledExpr::Constant(c)),
}
}
}