use std::sync::Arc;
use crate::ast::{JitType, PortType, ReflectedValue, SliceArc, SlotType, Value};
use crate::dsl::factory::ConstArg;
pub trait Wire: Sized + 'static {
const PORT: PortType;
const JIT: Option<JitType>;
const RESOLVER: Option<crate::dsl::registry::DefaultResolver> = None;
const WIRE_COST: crate::ast::WireCost = crate::ast::WireCost::Data;
fn extract(v: &Value) -> Self;
fn inject(self) -> Value;
}
impl Wire for u64 {
const PORT: PortType = PortType::U64;
const JIT: Option<JitType> = Some(JitType::U64);
fn extract(v: &Value) -> Self { v.as_u64() }
fn inject(self) -> Value { Value::U64(self) }
}
impl Wire for u32 {
const PORT: PortType = PortType::U32;
const JIT: Option<JitType> = Some(JitType::U64);
fn extract(v: &Value) -> Self { v.as_u64() as u32 }
fn inject(self) -> Value { Value::U64(self as u64) }
}
impl Wire for i32 {
const PORT: PortType = PortType::I32;
const JIT: Option<JitType> = Some(JitType::I64);
fn extract(v: &Value) -> Self { v.as_i64() as i32 }
fn inject(self) -> Value { Value::I64(self as i64) }
}
impl Wire for i64 {
const PORT: PortType = PortType::I64;
const JIT: Option<JitType> = Some(JitType::I64);
fn extract(v: &Value) -> Self { v.as_i64() }
fn inject(self) -> Value { Value::I64(self) }
}
impl Wire for u8 {
const PORT: PortType = PortType::U8;
const JIT: Option<JitType> = Some(JitType::U64);
fn extract(v: &Value) -> Self { v.as_u64() as u8 }
fn inject(self) -> Value { Value::U64(self as u64) }
}
impl Wire for u16 {
const PORT: PortType = PortType::U16;
const JIT: Option<JitType> = Some(JitType::U64);
fn extract(v: &Value) -> Self { v.as_u64() as u16 }
fn inject(self) -> Value { Value::U64(self as u64) }
}
impl Wire for i8 {
const PORT: PortType = PortType::I8;
const JIT: Option<JitType> = Some(JitType::I64);
fn extract(v: &Value) -> Self { v.as_i64() as i8 }
fn inject(self) -> Value { Value::I64(self as i64) }
}
impl Wire for i16 {
const PORT: PortType = PortType::I16;
const JIT: Option<JitType> = Some(JitType::I64);
fn extract(v: &Value) -> Self { v.as_i64() as i16 }
fn inject(self) -> Value { Value::I64(self as i64) }
}
impl Wire for u128 {
const PORT: PortType = PortType::U128;
const JIT: Option<JitType> = None;
fn extract(v: &Value) -> Self { v.as_u128() }
fn inject(self) -> Value { Value::U128(crate::ast::Bits128::from_u128(self)) }
}
impl Wire for i128 {
const PORT: PortType = PortType::I128;
const JIT: Option<JitType> = None;
fn extract(v: &Value) -> Self { v.as_i128() }
fn inject(self) -> Value { Value::I128(crate::ast::Bits128::from_i128(self)) }
}
impl Wire for crate::ast::Bits128 {
const PORT: PortType = PortType::Reg128;
const JIT: Option<JitType> = None;
fn extract(v: &Value) -> Self { v.as_reg_bits() }
fn inject(self) -> Value {
Value::Reg128(self, crate::ast::RegLanes::Raw)
}
}
macro_rules! impl_wire_reg {
($arr:ty, $port:ident, $view:ident, $to:ident, $from:ident) => {
impl Wire for $arr {
const PORT: PortType = PortType::$port;
const JIT: Option<JitType> = None;
fn extract(v: &Value) -> Self { v.as_reg_bits().$to() }
fn inject(self) -> Value {
Value::Reg128(
crate::ast::Bits128::$from(self),
crate::ast::RegLanes::$view,
)
}
}
};
}
impl_wire_reg!([i8; 16], RegI8x16, I8x16, lanes_i8, from_lanes_i8);
impl_wire_reg!([i16; 8], RegI16x8, I16x8, lanes_i16, from_lanes_i16);
impl_wire_reg!([i32; 4], RegI32x4, I32x4, lanes_i32, from_lanes_i32);
impl_wire_reg!([i64; 2], RegI64x2, I64x2, lanes_i64, from_lanes_i64);
impl_wire_reg!([half::f16; 8], RegF16x8, F16x8, lanes_f16, from_lanes_f16);
impl_wire_reg!([f32; 4], RegF32x4, F32x4, lanes_f32, from_lanes_f32);
impl_wire_reg!([f64; 2], RegF64x2, F64x2, lanes_f64, from_lanes_f64);
impl Wire for f64 {
const PORT: PortType = PortType::F64;
const JIT: Option<JitType> = Some(JitType::F64);
fn extract(v: &Value) -> Self { v.as_f64() }
fn inject(self) -> Value { Value::F64(self) }
}
impl Wire for f32 {
const PORT: PortType = PortType::F32;
const JIT: Option<JitType> = Some(JitType::U64);
fn extract(v: &Value) -> Self { f32::from_bits(v.as_u64() as u32) }
fn inject(self) -> Value { Value::U64(self.to_bits() as u64) }
}
impl Wire for half::f16 {
const PORT: PortType = PortType::F16;
const JIT: Option<JitType> = Some(JitType::U64);
fn extract(v: &Value) -> Self { half::f16::from_bits(v.as_u64() as u16) }
fn inject(self) -> Value { Value::U64(self.to_bits() as u64) }
}
impl Wire for bool {
const PORT: PortType = PortType::Bool;
const JIT: Option<JitType> = Some(JitType::Bool);
fn extract(v: &Value) -> Self {
match v {
Value::Bool(b) => *b,
Value::U64(n) => *n != 0,
other => panic!(
"Wire<bool>::extract: type-checker routed {other:?} \
to a Bool slot"),
}
}
fn inject(self) -> Value { Value::Bool(self) }
}
impl Wire for String {
const PORT: PortType = PortType::Str;
const JIT: Option<JitType> = Some(JitType::Str);
fn extract(v: &Value) -> Self {
match v {
Value::Str(s) => s.to_string(),
other => panic!(
"Wire<String>::extract: expected Str, got {other:?}"),
}
}
fn inject(self) -> Value { Value::Str(self.into()) }
}
impl Wire for std::sync::Arc<str> {
const PORT: PortType = PortType::Str;
const JIT: Option<JitType> = Some(JitType::Str);
fn extract(v: &Value) -> Self {
match v {
Value::Str(s) => s.clone(),
other => panic!(
"Wire<Arc<str>>::extract: expected Str, got {other:?}"),
}
}
fn inject(self) -> Value { Value::Str(self) }
}
impl Wire for std::sync::Arc<dyn std::any::Any + Send + Sync> {
const PORT: PortType = PortType::Handle;
const JIT: Option<JitType> = None;
fn extract(v: &Value) -> Self {
match v {
Value::Handle(arc) => arc.clone(),
other => panic!(
"Wire<Arc<dyn Any>>::extract: expected Handle, got {other:?}"),
}
}
fn inject(self) -> Value { Value::Handle(self) }
}
impl Wire for Box<dyn ReflectedValue> {
const PORT: PortType = PortType::Ext;
const JIT: Option<JitType> = None;
fn extract(v: &Value) -> Self {
match v {
Value::Ext(b) => b.clone_reflected(),
other => panic!(
"Wire<Box<dyn ReflectedValue>>::extract: expected Ext, got {other:?}"),
}
}
fn inject(self) -> Value { Value::Ext(self) }
}
impl Wire for Arc<[u8]> {
const PORT: PortType = PortType::Bytes;
const JIT: Option<JitType> = None;
fn extract(v: &Value) -> Self {
match v {
Value::Bytes(b) => b.clone(),
other => panic!("Wire<Arc<[u8]>>::extract: expected Bytes, got {other:?}"),
}
}
fn inject(self) -> Value { Value::Bytes(self) }
}
impl Wire for Vec<u8> {
const PORT: PortType = PortType::Bytes;
const JIT: Option<JitType> = None;
fn extract(v: &Value) -> Self {
match v {
Value::Bytes(b) => b.to_vec(),
other => panic!("Wire<Vec<u8>>::extract: expected Bytes, got {other:?}"),
}
}
fn inject(self) -> Value { Value::Bytes(self.into()) }
}
impl Wire for Arc<serde_json::Value> {
const PORT: PortType = PortType::Json;
const JIT: Option<JitType> = None;
fn extract(v: &Value) -> Self {
match v {
Value::Json(j) => j.clone(),
other => panic!("Wire<Arc<Json>>::extract: expected Json, got {other:?}"),
}
}
fn inject(self) -> Value { Value::Json(self) }
}
macro_rules! impl_wire_vec {
($elem:ty, $variant:ident, $port:ident) => {
impl Wire for SliceArc<$elem> {
const PORT: PortType = PortType::$port;
const JIT: Option<JitType> = None;
fn extract(v: &Value) -> Self {
match v {
Value::$variant(arc) => arc.clone(),
other => panic!(
concat!("Wire<SliceArc<", stringify!($elem),
">>::extract: expected ", stringify!($variant),
", got {:?}"),
other),
}
}
fn inject(self) -> Value { Value::$variant(self) }
}
impl Wire for Vec<$elem> {
const PORT: PortType = PortType::$port;
const JIT: Option<JitType> = None;
fn extract(v: &Value) -> Self {
match v {
Value::$variant(arc) => arc.as_slice().to_vec(),
other => panic!(
concat!("Wire<Vec<", stringify!($elem),
">>::extract: expected ", stringify!($variant),
", got {:?}"),
other),
}
}
fn inject(self) -> Value {
Value::$variant(SliceArc::from_vec(self))
}
}
};
}
impl_wire_vec!(f32, VecF32, VecF32);
impl_wire_vec!(i32, VecI32, VecI32);
impl_wire_vec!(f64, VecF64, VecF64);
impl_wire_vec!(i64, VecI64, VecI64);
impl_wire_vec!(half::f16, VecF16, VecF16);
impl_wire_vec!(i16, VecI16, VecI16);
impl_wire_vec!(i8, VecI8, VecI8);
impl<T: Wire> Wire for Option<T> {
const PORT: PortType = T::PORT;
const JIT: Option<JitType> = None;
fn extract(v: &Value) -> Self {
match v {
Value::None => None,
_ => Some(T::extract(v)),
}
}
fn inject(self) -> Value {
match self {
None => Value::None,
Some(t) => t.inject(),
}
}
}
pub struct Ext<T>(pub T);
impl<T> std::ops::Deref for Ext<T> {
type Target = T;
fn deref(&self) -> &T { &self.0 }
}
impl<T> std::ops::DerefMut for Ext<T> {
fn deref_mut(&mut self) -> &mut T { &mut self.0 }
}
impl<T: ReflectedValue + Clone + 'static> Wire for Ext<T> {
const PORT: PortType = PortType::Ext;
const JIT: Option<JitType> = None;
fn extract(v: &Value) -> Self {
match v {
Value::Ext(boxed) => {
let any = boxed.as_any();
match any.downcast_ref::<T>() {
Some(t) => Ext(t.clone()),
None => panic!(
"Wire<Ext<{}>>::extract: ReflectedValue downcast failed; \
got runtime type {:?}",
std::any::type_name::<T>(),
boxed.type_name()),
}
}
other => panic!("Wire<Ext>::extract: expected Ext, got {other:?}"),
}
}
fn inject(self) -> Value {
Value::Ext(Box::new(self.0))
}
}
pub struct DynamicOutputs<T>(pub Vec<T>);
impl<T> std::ops::Deref for DynamicOutputs<T> {
type Target = Vec<T>;
fn deref(&self) -> &Vec<T> { &self.0 }
}
pub struct Config<T>(pub T);
impl<T> std::ops::Deref for Config<T> {
type Target = T;
fn deref(&self) -> &T { &self.0 }
}
impl<T: Wire> Wire for Config<T> {
const PORT: PortType = T::PORT;
const JIT: Option<JitType> = T::JIT;
const RESOLVER: Option<crate::dsl::registry::DefaultResolver> = T::RESOLVER;
const WIRE_COST: crate::ast::WireCost = crate::ast::WireCost::Config;
fn extract(v: &Value) -> Self { Config(T::extract(v)) }
fn inject(self) -> Value { self.0.inject() }
}
pub struct Resolved<R: ResolverKind, T: 'static + Send + Sync> {
inner: std::sync::Arc<T>,
_r: std::marker::PhantomData<fn() -> R>,
}
impl<R: ResolverKind, T: 'static + Send + Sync> std::ops::Deref for Resolved<R, T> {
type Target = T;
fn deref(&self) -> &T { &self.inner }
}
impl<R: ResolverKind, T: 'static + Send + Sync> Resolved<R, T> {
pub fn from_arc(inner: std::sync::Arc<T>) -> Self {
Self { inner, _r: std::marker::PhantomData }
}
pub fn as_arc(&self) -> &std::sync::Arc<T> { &self.inner }
}
pub trait ResolverKind: 'static {
const RESOLVER: crate::dsl::registry::DefaultResolver;
}
pub struct GroupResolver;
impl ResolverKind for GroupResolver {
const RESOLVER: crate::dsl::registry::DefaultResolver =
crate::dsl::registry::DefaultResolver::Group;
}
impl<R: ResolverKind, T: 'static + Send + Sync> Wire for Resolved<R, T> {
const PORT: PortType = PortType::Handle;
const JIT: Option<JitType> = None;
const RESOLVER: Option<crate::dsl::registry::DefaultResolver> =
Some(<R as ResolverKind>::RESOLVER);
fn extract(v: &Value) -> Self {
match v {
Value::Handle(arc) => {
let inner = arc.clone().downcast::<T>()
.unwrap_or_else(|_| panic!(
"Wire<Resolved<_, {}>>::extract: Handle downcast failed",
std::any::type_name::<T>()));
Resolved { inner, _r: std::marker::PhantomData }
}
other => panic!(
"Wire<Resolved>::extract: expected Handle, got {other:?}"),
}
}
fn inject(self) -> Value { Value::Handle(self.inner) }
}
pub trait ConstSource: Sized + 'static {
const SLOT: SlotType;
fn extract(arg: &ConstArg) -> Self;
}
impl ConstSource for u64 {
const SLOT: SlotType = SlotType::ConstU64;
fn extract(arg: &ConstArg) -> Self {
match arg {
ConstArg::Int(v) => *v,
other => panic!("ConstSource<u64>::extract: expected Int, got {other:?}"),
}
}
}
impl ConstSource for f64 {
const SLOT: SlotType = SlotType::ConstF64;
fn extract(arg: &ConstArg) -> Self {
match arg {
ConstArg::Float(v) => *v,
ConstArg::Int(v) => *v as f64,
other => panic!("ConstSource<f64>::extract: expected Float or Int, got {other:?}"),
}
}
}
impl ConstSource for bool {
const SLOT: SlotType = SlotType::ConstU64;
fn extract(arg: &ConstArg) -> Self {
match arg {
ConstArg::Int(v) => *v != 0,
other => panic!("ConstSource<bool>::extract: expected Int, got {other:?}"),
}
}
}
impl ConstSource for String {
const SLOT: SlotType = SlotType::ConstStr;
fn extract(arg: &ConstArg) -> Self {
match arg {
ConstArg::Str(s) => s.clone(),
other => panic!("ConstSource<String>::extract: expected Str, got {other:?}"),
}
}
}
impl<C: ConstSource> ConstSource for Vec<C> {
const SLOT: SlotType = SlotType::ConstVec;
fn extract(arg: &ConstArg) -> Self {
match arg {
ConstArg::List(items) => items.iter().map(C::extract).collect(),
other => panic!(
"ConstSource<Vec<_>>::extract: expected List, got {other:?}"),
}
}
}
pub struct Const<T>(pub T);
impl<T> std::ops::Deref for Const<T> {
type Target = T;
fn deref(&self) -> &T { &self.0 }
}
impl<T> std::ops::DerefMut for Const<T> {
fn deref_mut(&mut self) -> &mut T { &mut self.0 }
}
pub trait PolydatSetup {}