coremem_types: DiscrMat2: implement in terms of compound::list::List

i'm not happy AT ALL with this implementation,
but it's the first way i've found which works around ZST limitations.
This commit is contained in:
2022-07-20 16:20:09 -07:00
parent d034453970
commit b555ee93f0
2 changed files with 104 additions and 108 deletions

View File

@@ -3,105 +3,118 @@ use crate::compound::peano::{P0, Peano, PNext};
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
use serde::{Serialize, Deserialize}; use serde::{Serialize, Deserialize};
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub trait TuplePrims: Sized {
#[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<H, T> {
head: H,
// Null or Node
tail: T,
}
impl<H, T> Node<H, T> {
fn new(head: H, tail: T) -> Self {
Self { head, tail }
}
}
pub trait Chomp {
type Head; // single element type Head; // single element
type Tail; // variably-sized tuple 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<E0> Chomp for (E0,) { impl<E0> TuplePrims for (E0,) {
type Head = E0; type Head = E0;
type Tail = (); type Tail = ();
fn chomp(self) -> (Self::Head, Self::Tail) { fn into_head(self) -> Self::Head {
(self.0, ()) self.0
}
fn into_tail(self) -> Self::Tail {
()
} }
} }
impl<E0, E1> Chomp for (E0, E1) { impl<E0, E1> TuplePrims for (E0, E1) {
type Head = E0; type Head = E0;
type Tail = (E1,); type Tail = (E1,);
fn chomp(self) -> (Self::Head, Self::Tail) { fn into_head(self) -> Self::Head {
(self.0, (self.1,)) self.0
}
fn into_tail(self) -> Self::Tail {
(self.1,)
} }
} }
impl<E0, E1, E2> Chomp for (E0, E1, E2) { impl<E0, E1, E2> TuplePrims for (E0, E1, E2) {
type Head = E0; type Head = E0;
type Tail = (E1, E2); type Tail = (E1, E2);
fn chomp(self) -> (Self::Head, Self::Tail) { fn into_head(self) -> Self::Head {
(self.0, (self.1, self.2)) self.0
}
fn into_tail(self) -> Self::Tail {
(self.1, self.2)
} }
} }
impl<E0, E1, E2, E3> Chomp for (E0, E1, E2, E3) { impl<E0, E1, E2, E3> TuplePrims for (E0, E1, E2, E3) {
type Head = E0; type Head = E0;
type Tail = (E1, E2, E3); type Tail = (E1, E2, E3);
fn chomp(self) -> (Self::Head, Self::Tail) { fn into_head(self) -> Self::Head {
(self.0, (self.1, self.2, self.3)) 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<Args> IntoList for Args
where
Args: Chomp,
Args::Tail: IntoList,
{
type List = Node<Args::Head, <<Args as Chomp>::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), // note that this construction allows a zero-length list (Null),
// which is sort of interesting. // which is sort of interesting.
pub type List<Args> = <Args as IntoList>::List; #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[cfg_attr(feature = "fmt", derive(Debug))]
#[derive(Copy, Clone, Default, PartialEq)]
pub struct List<Args>(Args);
// zero-index into Self impl<Args> List<Args> {
impl<H, T> core::ops::Index<P0> for Node<H, T> { pub fn new(args: Args) -> Self {
type Output = H; Self(args)
fn index(&self, _: P0) -> &Self::Output {
&self.head
} }
} }
// index N+1 into Self given that we know how to index N into Self::next pub trait ListPrims: Sized {
impl<H, T, P> core::ops::Index<PNext<P>> for Node<H, T> type Head; // single element
type Tail; // variably-sized List
fn into_head(self) -> Self::Head;
fn into_tail(self) -> Self::Tail;
}
impl<Args: TuplePrims> ListPrims for List<Args> {
type Head = Args::Head;
type Tail = List<Args::Tail>;
fn into_head(self) -> Self::Head {
self.0.into_head()
}
fn into_tail(self) -> Self::Tail {
List(self.0.into_tail())
}
}
pub trait Consumable<P> {
type Result: ListPrims;
fn consume(self) -> Self::Result;
}
impl<Args: TuplePrims> Consumable<P0> for List<Args> {
type Result = Self;
fn consume(self) -> Self::Result {
self
}
}
impl<Args, P> Consumable<PNext<P>> for List<Args>
where where
P: Peano, Self: ListPrims,
T: core::ops::Index<P>, <Self as ListPrims>::Tail: Consumable<P>,
{ {
type Output = T::Output; type Result = <<Self as ListPrims>::Tail as Consumable<P>>::Result;
fn index(&self, _: PNext<P>) -> &Self::Output { fn consume(self) -> Self::Result {
self.tail.index(P::default()) self.into_tail().consume()
}
}
impl<Args: TuplePrims> List<Args> {
pub fn consume<P>(self) -> <Self as Consumable<P>>::Result
where Self: Consumable<P>
{
Consumable::<P>::consume(self)
}
pub fn get<P>(self) -> <<Self as Consumable<P>>::Result as ListPrims>::Head
where Self: Consumable<P>
{
self.consume().into_head()
} }
} }
@@ -113,20 +126,12 @@ mod test {
use core::cell::Cell; use core::cell::Cell;
#[test] #[test]
fn test_into_list() { fn get() {
let list = (5u32, 4i32, 3f32).into_list(); let list = List((5u32, 4i32, 3f32));
assert_eq!(list[P0::default()], 5u32); assert_eq!(list.get::<P0>(), 5u32);
assert_eq!(list[P1::default()], 4i32); assert_eq!(list.get::<P1>(), 4i32);
assert_eq!(list[P2::default()], 3f32); assert_eq!(list.get::<P2>(), 3f32);
}
#[test]
fn test_list_default() {
let defaulted = List::<(i32, f32, u32)>::default();
let explicit = (0i32, 0f32, 0u32).into_list();
assert!(defaulted == explicit);
} }
// #[test] // #[test]

View File

@@ -1,5 +1,7 @@
use crate::real::Real; use crate::real::Real;
use crate::vec::Vec3; use crate::vec::Vec3;
use crate::compound::list::{List, ListPrims as _};
use crate::compound::peano::{P0, P1};
mod conductor; mod conductor;
mod mb_pgram; mod mb_pgram;
@@ -30,20 +32,17 @@ pub trait DiscriminantCodable {
fn make_discr(d: u32) -> Self; fn make_discr(d: u32) -> Self;
} }
pub struct D0<T>(pub T);
pub struct D1<T>(pub T);
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[cfg_attr(feature = "fmt", derive(Debug))] #[cfg_attr(feature = "fmt", derive(Debug))]
#[derive(Copy, Clone, Default, PartialEq)] #[derive(Copy, Clone, Default, PartialEq)]
pub struct DiscrMat2<M0, M1> { pub struct DiscrMat2<M0, M1>(List<(M0, M1)>);
m0: M0,
m1: M1, pub struct D0<T>(pub T);
} pub struct D1<T>(pub T);
impl<M0, M1> DiscrMat2<M0, M1> { impl<M0, M1> DiscrMat2<M0, M1> {
fn new_from_fields(m0: M0, m1: M1) -> Self { fn new_from_fields(m0: M0, m1: M1) -> Self {
Self { m0, m1 } Self(List::new((m0, m1)))
} }
} }
@@ -71,27 +70,19 @@ impl<M0: DiscriminantCodable, M1> From<D1<M1>> for DiscrMat2<M0, M1> {
} }
} }
impl<R: Real, M0: DiscriminantCodable + Material<R>, M1: Material<R> + Copy> Material<R> for DiscrMat2<M0, M1> { impl<R: Real, M0: DiscriminantCodable + Material<R> + Copy, M1: Material<R> + Copy> Material<R> for DiscrMat2<M0, M1> {
fn conductivity(&self) -> Vec3<R> { fn conductivity(&self) -> Vec3<R> {
match self.m0.discr() { match self.0.get::<P0>().discr() {
0 => self.m0.conductivity(), 0 => self.0.get::<P0>().conductivity(),
1 => { 1 => self.0.get::<P1>().conductivity(),
let mat = self.m1; //< XXX hack for ZST _ => unreachable!(),
mat.conductivity()
}
_ => panic!()
// _ => unreachable!(),
} }
} }
fn move_b_vec(&self, m: Vec3<R>, target_b: Vec3<R>) -> Vec3<R> { fn move_b_vec(&self, m: Vec3<R>, target_b: Vec3<R>) -> Vec3<R> {
match self.m0.discr() { match self.0.into_head().discr() {
0 => self.m0.move_b_vec(m, target_b), 0 => self.0.get::<P0>().move_b_vec(m, target_b),
1 => { 1 => self.0.get::<P1>().move_b_vec(m, target_b),
let mat = self.m1; //< XXX hack for ZST _ => unreachable!(),
mat.move_b_vec(m, target_b)
}
_ => panic!()
// _ => unreachable!(),
} }
} }
} }