diff --git a/crates/types/src/compound/list.rs b/crates/types/src/compound/list.rs index d1b0cde..45fe33e 100644 --- a/crates/types/src/compound/list.rs +++ b/crates/types/src/compound/list.rs @@ -3,105 +3,118 @@ use crate::compound::peano::{P0, Peano, PNext}; #[cfg(feature = "serde")] use serde::{Serialize, Deserialize}; -#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] -#[cfg_attr(feature = "fmt", derive(Debug))] -#[derive(Copy, Clone, Default, PartialEq)] -pub struct Null; - -#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] -#[cfg_attr(feature = "fmt", derive(Debug))] -#[derive(Copy, Clone, Default, PartialEq)] -pub struct Node { - head: H, - // Null or Node - tail: T, -} - -impl Node { - fn new(head: H, tail: T) -> Self { - Self { head, tail } - } -} - -pub trait Chomp { +pub trait TuplePrims: Sized { type Head; // single element type Tail; // variably-sized tuple - fn chomp(self) -> (Self::Head, Self::Tail); + fn into_head(self) -> Self::Head; + fn into_tail(self) -> Self::Tail; } -impl Chomp for (E0,) { +impl TuplePrims for (E0,) { type Head = E0; type Tail = (); - fn chomp(self) -> (Self::Head, Self::Tail) { - (self.0, ()) + fn into_head(self) -> Self::Head { + self.0 + } + fn into_tail(self) -> Self::Tail { + () } } -impl Chomp for (E0, E1) { +impl TuplePrims for (E0, E1) { type Head = E0; type Tail = (E1,); - fn chomp(self) -> (Self::Head, Self::Tail) { - (self.0, (self.1,)) + fn into_head(self) -> Self::Head { + self.0 + } + fn into_tail(self) -> Self::Tail { + (self.1,) } } -impl Chomp for (E0, E1, E2) { +impl TuplePrims for (E0, E1, E2) { type Head = E0; type Tail = (E1, E2); - fn chomp(self) -> (Self::Head, Self::Tail) { - (self.0, (self.1, self.2)) + fn into_head(self) -> Self::Head { + self.0 + } + fn into_tail(self) -> Self::Tail { + (self.1, self.2) } } -impl Chomp for (E0, E1, E2, E3) { +impl TuplePrims for (E0, E1, E2, E3) { type Head = E0; type Tail = (E1, E2, E3); - fn chomp(self) -> (Self::Head, Self::Tail) { - (self.0, (self.1, self.2, self.3)) + fn into_head(self) -> Self::Head { + self.0 + } + fn into_tail(self) -> Self::Tail { + (self.1, self.2, self.3) } } -pub trait IntoList { - type List; - fn into_list(self) -> Self::List; -} - -impl IntoList for Args -where - Args: Chomp, - Args::Tail: IntoList, -{ - type List = Node::Tail as IntoList>::List>; - fn into_list(self) -> Self::List { - let (head, tail) = self.chomp(); - Node::new(head, tail.into_list()) - } -} - -impl IntoList for () { - type List = Null; - fn into_list(self) -> Self::List { - Null - } -} // note that this construction allows a zero-length list (Null), // which is sort of interesting. -pub type List = ::List; +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] +#[cfg_attr(feature = "fmt", derive(Debug))] +#[derive(Copy, Clone, Default, PartialEq)] +pub struct List(Args); -// zero-index into Self -impl core::ops::Index for Node { - type Output = H; - fn index(&self, _: P0) -> &Self::Output { - &self.head +impl List { + pub fn new(args: Args) -> Self { + Self(args) } } -// index N+1 into Self given that we know how to index N into Self::next -impl core::ops::Index> for Node +pub trait ListPrims: Sized { + type Head; // single element + type Tail; // variably-sized List + fn into_head(self) -> Self::Head; + fn into_tail(self) -> Self::Tail; +} + +impl ListPrims for List { + type Head = Args::Head; + type Tail = List; + fn into_head(self) -> Self::Head { + self.0.into_head() + } + fn into_tail(self) -> Self::Tail { + List(self.0.into_tail()) + } +} + +pub trait Consumable

{ + type Result: ListPrims; + fn consume(self) -> Self::Result; +} + +impl Consumable for List { + type Result = Self; + fn consume(self) -> Self::Result { + self + } +} + +impl Consumable> for List where - P: Peano, - T: core::ops::Index

, + Self: ListPrims, + ::Tail: Consumable

, { - type Output = T::Output; - fn index(&self, _: PNext

) -> &Self::Output { - self.tail.index(P::default()) + type Result = <::Tail as Consumable

>::Result; + fn consume(self) -> Self::Result { + self.into_tail().consume() + } +} + +impl List { + pub fn consume

(self) -> >::Result + where Self: Consumable

+ { + Consumable::

::consume(self) + } + pub fn get

(self) -> <>::Result as ListPrims>::Head + where Self: Consumable

+ { + self.consume().into_head() } } @@ -113,20 +126,12 @@ mod test { use core::cell::Cell; #[test] - fn test_into_list() { - let list = (5u32, 4i32, 3f32).into_list(); + fn get() { + let list = List((5u32, 4i32, 3f32)); - assert_eq!(list[P0::default()], 5u32); - assert_eq!(list[P1::default()], 4i32); - assert_eq!(list[P2::default()], 3f32); - } - - #[test] - fn test_list_default() { - let defaulted = List::<(i32, f32, u32)>::default(); - let explicit = (0i32, 0f32, 0u32).into_list(); - - assert!(defaulted == explicit); + assert_eq!(list.get::(), 5u32); + assert_eq!(list.get::(), 4i32); + assert_eq!(list.get::(), 3f32); } // #[test] diff --git a/crates/types/src/mat/mod.rs b/crates/types/src/mat/mod.rs index b708c59..5fad896 100644 --- a/crates/types/src/mat/mod.rs +++ b/crates/types/src/mat/mod.rs @@ -1,5 +1,7 @@ use crate::real::Real; use crate::vec::Vec3; +use crate::compound::list::{List, ListPrims as _}; +use crate::compound::peano::{P0, P1}; mod conductor; mod mb_pgram; @@ -30,20 +32,17 @@ pub trait DiscriminantCodable { fn make_discr(d: u32) -> Self; } -pub struct D0(pub T); -pub struct D1(pub T); - #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] #[cfg_attr(feature = "fmt", derive(Debug))] #[derive(Copy, Clone, Default, PartialEq)] -pub struct DiscrMat2 { - m0: M0, - m1: M1, -} +pub struct DiscrMat2(List<(M0, M1)>); + +pub struct D0(pub T); +pub struct D1(pub T); impl DiscrMat2 { fn new_from_fields(m0: M0, m1: M1) -> Self { - Self { m0, m1 } + Self(List::new((m0, m1))) } } @@ -71,27 +70,19 @@ impl From> for DiscrMat2 { } } -impl, M1: Material + Copy> Material for DiscrMat2 { +impl + Copy, M1: Material + Copy> Material for DiscrMat2 { fn conductivity(&self) -> Vec3 { - match self.m0.discr() { - 0 => self.m0.conductivity(), - 1 => { - let mat = self.m1; //< XXX hack for ZST - mat.conductivity() - } - _ => panic!() - // _ => unreachable!(), + match self.0.get::().discr() { + 0 => self.0.get::().conductivity(), + 1 => self.0.get::().conductivity(), + _ => unreachable!(), } } fn move_b_vec(&self, m: Vec3, target_b: Vec3) -> Vec3 { - match self.m0.discr() { - 0 => self.m0.move_b_vec(m, target_b), - 1 => { - let mat = self.m1; //< XXX hack for ZST - mat.move_b_vec(m, target_b) - } - _ => panic!() - // _ => unreachable!(), + match self.0.into_head().discr() { + 0 => self.0.get::().move_b_vec(m, target_b), + 1 => self.0.get::().move_b_vec(m, target_b), + _ => unreachable!(), } } }