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")]
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<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 {
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<E0> Chomp for (E0,) {
impl<E0> 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<E0, E1> Chomp for (E0, E1) {
impl<E0, E1> 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<E0, E1, E2> Chomp for (E0, E1, E2) {
impl<E0, E1, E2> 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<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 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<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),
// 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<H, T> core::ops::Index<P0> for Node<H, T> {
type Output = H;
fn index(&self, _: P0) -> &Self::Output {
&self.head
impl<Args> List<Args> {
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<H, T, P> core::ops::Index<PNext<P>> for Node<H, T>
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<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
P: Peano,
T: core::ops::Index<P>,
Self: ListPrims,
<Self as ListPrims>::Tail: Consumable<P>,
{
type Output = T::Output;
fn index(&self, _: PNext<P>) -> &Self::Output {
self.tail.index(P::default())
type Result = <<Self as ListPrims>::Tail as Consumable<P>>::Result;
fn consume(self) -> Self::Result {
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;
#[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::<P0>(), 5u32);
assert_eq!(list.get::<P1>(), 4i32);
assert_eq!(list.get::<P2>(), 3f32);
}
// #[test]

View File

@@ -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<T>(pub T);
pub struct D1<T>(pub T);
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[cfg_attr(feature = "fmt", derive(Debug))]
#[derive(Copy, Clone, Default, PartialEq)]
pub struct DiscrMat2<M0, M1> {
m0: M0,
m1: M1,
}
pub struct DiscrMat2<M0, M1>(List<(M0, M1)>);
pub struct D0<T>(pub T);
pub struct D1<T>(pub T);
impl<M0, M1> DiscrMat2<M0, M1> {
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> {
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::<P0>().discr() {
0 => self.0.get::<P0>().conductivity(),
1 => self.0.get::<P1>().conductivity(),
_ => unreachable!(),
}
}
fn move_b_vec(&self, m: Vec3<R>, target_b: Vec3<R>) -> Vec3<R> {
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::<P0>().move_b_vec(m, target_b),
1 => self.0.get::<P1>().move_b_vec(m, target_b),
_ => unreachable!(),
}
}
}