use std::{
any::{TypeId, type_name},
collections::HashMap,
net::IpAddr,
sync::{Arc, LazyLock, Mutex},
};
use inetnum::{addr::Prefix, asn::Asn};
use sealed::sealed;
use crate::{
lir::{IrValue, Memory},
runtime::layout::Layout,
};
pub use dyn_val::DynVal;
pub(crate) use list::ErasedList;
pub use list::boundary::List;
pub use option::RotoOption;
pub use val::Val;
pub use verdict::Verdict;
pub use vtable::VTable;
mod dyn_val;
pub mod list;
mod option;
mod val;
mod verdict;
mod vtable;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum TypeDescription {
Leaf,
Option(TypeId),
Verdict(TypeId, TypeId),
List(TypeId),
Val(TypeId),
}
#[derive(Clone)]
pub struct Ty {
pub rust_name: &'static str,
pub layout: Layout,
pub type_id: TypeId,
pub description: TypeDescription,
}
impl Ty {
fn new<T: 'static>(description: TypeDescription) -> Self {
Self {
rust_name: type_name::<T>(),
layout: Layout::of::<T>(),
type_id: TypeId::of::<T>(),
description,
}
}
}
static GLOBAL_TYPE_REGISTRY: LazyLock<Mutex<TypeRegistry>> =
LazyLock::new(|| Mutex::new(TypeRegistry::default()));
#[derive(Clone, Default)]
pub struct TypeRegistry {
map: HashMap<TypeId, &'static Ty>,
}
impl TypeRegistry {
pub fn store<T: 'static>(description: TypeDescription) -> Ty {
let ty = Ty::new::<T>(description);
GLOBAL_TYPE_REGISTRY
.lock()
.unwrap()
.map
.entry(ty.type_id)
.or_insert_with(|| {
Box::leak(Box::new(ty))
})
.clone()
}
pub fn get(id: TypeId) -> Option<&'static Ty> {
let registry = GLOBAL_TYPE_REGISTRY.lock().unwrap();
registry.map.get(&id).map(|v| &**v)
}
pub fn resolve<T: Value>() -> Ty {
T::resolve()
}
}
#[diagnostic::on_unimplemented(
note = "`Value` is implemented for Roto's built-in types and `Val<T>`.",
note = "You cannot implement `Value` for your own types but you can wrap them in `Val<T>`."
)]
#[sealed(pub(crate))]
pub trait Value: Sized + 'static {
type Transformed: Clone;
type AsParam: Param<Self::Transformed>;
fn transform(self) -> Self::Transformed;
fn untransform(transformed: Self::Transformed) -> Self;
fn as_param(transformed: &mut Self::Transformed) -> Self::AsParam {
Self::AsParam::as_param(transformed)
}
fn to_value(param: Self::AsParam) -> Self::Transformed {
Self::AsParam::to_value(param)
}
fn from_ir_value(
mem: &mut Memory,
value: IrValue,
) -> Result<Self::AsParam, IrValueDoesNotMatchType> {
Self::AsParam::from_ir_value(mem, value)
}
fn resolve() -> Ty;
fn name() -> &'static str {
std::any::type_name::<Self>()
}
}
pub struct IrValueDoesNotMatchType;
pub trait Param<T>: Sized {
fn as_param(value: &mut T) -> Self;
fn to_value(self) -> T;
fn from_ir_value(
mem: &mut Memory,
value: IrValue,
) -> Result<Self, IrValueDoesNotMatchType>;
}
impl<T> Param<T> for *mut T {
fn as_param(transformed: &mut T) -> Self {
transformed as *mut T
}
fn to_value(self) -> T {
unsafe { std::ptr::read(self) }
}
fn from_ir_value(
mem: &mut Memory,
value: IrValue,
) -> Result<Self, IrValueDoesNotMatchType> {
let IrValue::Pointer(p) = value else {
return Err(IrValueDoesNotMatchType);
};
Ok(mem.read_slice(p, std::mem::size_of::<T>()).as_ptr() as *mut T)
}
}
#[sealed]
impl<A: Value, R: Value> Value for Verdict<A, R>
where
A::Transformed: Clone,
R::Transformed: Clone,
{
type Transformed = Verdict<A::Transformed, R::Transformed>;
type AsParam = *mut Self::Transformed;
fn transform(self) -> Self::Transformed {
match self {
Self::Accept(a) => Verdict::Accept(a.transform()),
Self::Reject(r) => Verdict::Reject(r.transform()),
}
}
fn untransform(transformed: Self::Transformed) -> Self {
match transformed {
Verdict::Accept(a) => Self::Accept(A::untransform(a)),
Verdict::Reject(r) => Self::Reject(R::untransform(r)),
}
}
fn resolve() -> Ty {
let t = A::resolve().type_id;
let e = R::resolve().type_id;
let desc = TypeDescription::Verdict(t, e);
TypeRegistry::store::<Self>(desc)
}
}
#[sealed]
impl<T: Value> Value for Option<T> {
type Transformed = RotoOption<T::Transformed>;
type AsParam = *mut Self::Transformed;
fn transform(self) -> Self::Transformed {
match self {
Some(t) => RotoOption::Some(t.transform()),
None => RotoOption::None,
}
}
fn untransform(transformed: Self::Transformed) -> Self {
match transformed {
RotoOption::Some(t) => Some(T::untransform(t)),
RotoOption::None => None,
}
}
fn resolve() -> Ty {
let t = T::resolve().type_id;
let desc = TypeDescription::Option(t);
TypeRegistry::store::<Self>(desc)
}
}
impl<T> Param<Val<T>> for *mut T {
fn as_param(value: &mut Val<T>) -> Self {
&mut value.0 as *mut _
}
fn to_value(self) -> Val<T> {
Val(unsafe { std::ptr::read(self) })
}
fn from_ir_value(
mem: &mut Memory,
value: IrValue,
) -> Result<Self, IrValueDoesNotMatchType> {
let IrValue::Pointer(p) = value else {
return Err(IrValueDoesNotMatchType);
};
Ok(mem.read_slice(p, std::mem::size_of::<T>()).as_ptr() as *mut T)
}
}
#[sealed]
impl<T: 'static + Clone> Value for Val<T> {
type Transformed = Self;
type AsParam = *mut T;
fn transform(self) -> Self::Transformed {
self
}
fn untransform(transformed: Self::Transformed) -> Self {
transformed
}
fn resolve() -> Ty {
let t = TypeId::of::<T>();
let desc = TypeDescription::Val(t);
TypeRegistry::store::<Self>(desc)
}
fn name() -> &'static str {
std::any::type_name::<T>()
}
}
#[sealed]
impl Value for IpAddr {
type Transformed = Self;
type AsParam = *mut Self;
fn transform(self) -> Self::Transformed {
self
}
fn untransform(transformed: Self::Transformed) -> Self {
transformed
}
fn resolve() -> Ty {
TypeRegistry::store::<Self>(TypeDescription::Leaf)
}
}
#[sealed]
impl Value for Prefix {
type Transformed = Self;
type AsParam = *mut Self;
fn transform(self) -> Self::Transformed {
self
}
fn untransform(transformed: Self::Transformed) -> Self {
transformed
}
fn resolve() -> Ty {
TypeRegistry::store::<Self>(TypeDescription::Leaf)
}
}
#[sealed]
impl Value for Arc<str> {
type Transformed = Self;
type AsParam = *mut Self;
fn transform(self) -> Self::Transformed {
self
}
fn untransform(transformed: Self::Transformed) -> Self {
transformed
}
fn resolve() -> Ty {
TypeRegistry::store::<Self>(TypeDescription::Leaf)
}
}
#[sealed]
impl Value for ErasedList {
type Transformed = Self;
type AsParam = *mut Self;
fn transform(self) -> Self::Transformed {
self
}
fn untransform(transformed: Self::Transformed) -> Self {
transformed
}
fn resolve() -> Ty {
TypeRegistry::store::<Self>(TypeDescription::Leaf)
}
}
#[sealed]
impl<T: Value> Value for List<T> {
type Transformed = Self;
type AsParam = *mut Self;
fn transform(self) -> Self::Transformed {
self
}
fn untransform(transformed: Self::Transformed) -> Self {
transformed
}
fn resolve() -> Ty {
let t = T::resolve().type_id;
let desc = TypeDescription::List(t);
TypeRegistry::store::<Self>(desc)
}
}
#[sealed]
impl Value for VTable {
type Transformed = Self;
type AsParam = *mut Self;
fn transform(self) -> Self::Transformed {
self
}
fn untransform(transformed: Self::Transformed) -> Self {
transformed
}
fn resolve() -> Ty {
TypeRegistry::store::<Self>(TypeDescription::Leaf)
}
}
impl Param<DynVal> for DynVal {
fn as_param(value: &mut DynVal) -> Self {
*value
}
fn to_value(self) -> DynVal {
self
}
fn from_ir_value(
_mem: &mut Memory,
_value: IrValue,
) -> Result<Self, IrValueDoesNotMatchType> {
todo!()
}
}
#[sealed]
impl Value for DynVal {
type Transformed = Self;
type AsParam = Self;
fn transform(self) -> Self::Transformed {
self
}
fn untransform(transformed: Self::Transformed) -> Self {
transformed
}
fn resolve() -> Ty {
TypeRegistry::store::<Self>(TypeDescription::Leaf)
}
}
impl TryFrom<&IrValue> for () {
type Error = ();
fn try_from(_: &IrValue) -> Result<Self, Self::Error> {
Err(())
}
}
impl Param<()> for () {
fn as_param(_: &mut ()) -> Self {}
fn to_value(self) {}
fn from_ir_value(
_mem: &mut Memory,
_value: IrValue,
) -> Result<Self, IrValueDoesNotMatchType> {
Ok(())
}
}
#[sealed]
impl Value for () {
type Transformed = Self;
type AsParam = Self;
fn transform(self) -> Self::Transformed {
self
}
fn untransform(transformed: Self::Transformed) -> Self {
transformed
}
fn resolve() -> Ty {
TypeRegistry::store::<Self>(TypeDescription::Leaf)
}
}
macro_rules! simple_value {
($t:ty, $ir:ident) => {
impl From<$t> for IrValue {
fn from(value: $t) -> Self {
IrValue::$ir(value)
}
}
impl TryFrom<&IrValue> for $t {
type Error = ();
fn try_from(value: &IrValue) -> Result<Self, Self::Error> {
match value {
IrValue::$ir(x) => Ok(*x),
_ => Err(()),
}
}
}
impl Param<$t> for $t {
fn as_param(value: &mut $t) -> Self {
*value
}
fn to_value(self) -> $t {
self
}
fn from_ir_value(
_: &mut Memory,
value: IrValue,
) -> Result<Self, IrValueDoesNotMatchType> {
let IrValue::$ir(p) = value else {
return Err(IrValueDoesNotMatchType);
};
Ok(p)
}
}
#[sealed]
impl Value for $t {
type Transformed = Self;
type AsParam = Self;
fn transform(self) -> Self::Transformed {
self
}
fn untransform(transformed: Self::Transformed) -> Self {
transformed
}
fn resolve() -> Ty {
TypeRegistry::store::<Self>(TypeDescription::Leaf)
}
}
};
}
simple_value!(bool, Bool);
simple_value!(u8, U8);
simple_value!(u16, U16);
simple_value!(u32, U32);
simple_value!(u64, U64);
simple_value!(i8, I8);
simple_value!(i16, I16);
simple_value!(i32, I32);
simple_value!(i64, I64);
simple_value!(f32, F32);
simple_value!(f64, F64);
simple_value!(char, Char);
simple_value!(Asn, Asn);