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:
@@ -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]
|
||||
|
@@ -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!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user