macro_rules! trait_alias_impl {
([$($tokens:tt)*] $name:ident<$bound_name:ident: $bounds:tt> = $($defn:tt)+) => {
$($tokens)* trait $name<$bound_name: $bounds>: $($defn)+ {}
impl<$bound_name: $bounds, T: $($defn)+> $name<$bound_name> for T {}
};
([$($tokens:tt)*] $name:ident = $($defn:tt)+) => {
$($tokens)* trait $name: $($defn)+ {}
impl<T: $($defn)+> $name for T {}
};
}
macro_rules! trait_alias {
($(#[doc = $text:literal])* pub $($tokens:tt)+) => {
trait_alias_impl!{[$(#[doc = $text])* pub] $($tokens)*}
};
($($tokens:tt)+) => { trait_alias_impl!{[] $($tokens)*} };
}
pub trait AddIdentity: Eq + Sized {
fn add_id() -> Self;
fn is_add_id(&self) -> bool {
self == &Self::add_id()
}
}
pub trait MulIdentity: Eq + Sized {
fn mul_id() -> Self;
fn is_mul_id(&self) -> bool {
self == &Self::mul_id()
}
}
pub trait PartiallyInvertible: MulIdentity {
fn try_inverse(&self) -> Option<Self>;
}
pub trait Invertible: PartiallyInvertible {
fn inverse(&self) -> Self {
self.try_inverse().unwrap()
}
fn invert(&mut self) {
*self = self.inverse();
}
}
pub trait Binary {
type Rhs: ?Sized;
fn into_rhs(&self) -> &Self::Rhs;
}
trait_alias! {
pub Add = Binary + for<'a> std::ops::AddAssign<&'a Self::Rhs>
}
trait_alias! {
pub Sub = Binary + for<'a> std::ops::SubAssign<&'a Self::Rhs>
}
trait_alias! {
pub Mul = Binary + for<'a> std::ops::MulAssign<&'a Self::Rhs>
}
trait_alias! {
pub Div = Binary + for<'a> std::ops::DivAssign<&'a Self::Rhs>
}
trait_alias! {
pub Meet = PartialOrd + Binary + for<'a> std::ops::BitAndAssign<&'a Self::Rhs>
}
trait_alias! {
pub Join = PartialOrd + Binary + for<'a> std::ops::BitAndAssign<&'a Self::Rhs>
}
pub trait AddAssociative: Add {}
pub trait MulAssociative: Mul {}
pub trait MeetAssociative: Meet {}
pub trait JoinAssociative: Join {}
pub trait AddCommutative: Add {}
pub trait MulCommutative: Mul {}
pub trait MeetCommutative: Meet {}
pub trait JoinCommutative: Join {}
pub trait MeetIdempotent: Meet {}
pub trait JoinIdempotent: Join {}
pub trait AddMulDistributive: Add + Mul {}
pub trait Absorption: Meet + Join {}
pub trait Domain: Ring {}
trait_alias! {
pub AddSemigroup = AddAssociative
}
trait_alias! {
pub MulSemigroup = MulAssociative
}
trait_alias! {
pub AddMonoid = AddSemigroup + AddIdentity
}
trait_alias! {
pub MulMonoid = MulSemigroup + MulIdentity
}
trait_alias! {
pub AddGroup = AddMonoid + std::ops::Neg<Output=Self> + Sub
}
trait_alias! {
pub MulGroup = MulMonoid + Invertible
}
trait_alias! {
pub AbelianAddGroup = AddGroup + AddCommutative
}
trait_alias! {
pub AbelianMulGroup = MulGroup + MulCommutative
}
trait_alias! {
pub RingWithoutIdentity = AbelianAddGroup + MulSemigroup + AddMulDistributive
}
trait_alias! {
pub Ring = RingWithoutIdentity + MulIdentity
}
trait_alias! {
pub CommutativeRing = Ring + MulCommutative
}
trait_alias! {
pub MeetSemilattice = MeetCommutative + MeetAssociative + MeetIdempotent
}
trait_alias! {
pub JoinSemilattice = JoinCommutative + JoinAssociative + JoinIdempotent
}
trait_alias! {
pub Lattice = MeetSemilattice + JoinSemilattice + Absorption
}
trait_alias! {
pub IntegralDomain = CommutativeRing + Domain
}
trait_alias! {
pub DivisionRing = Ring + Div
}
trait_alias! {
pub Field = CommutativeRing + Div
}
#[cfg(feature = "polynomial")]
pub mod polynomial;
#[cfg(feature = "cyclic")]
pub mod cyclic;
macro_rules! implement {
($t:ty, [$($tr:ty,)*]) => { $(impl $tr for $t {})* };
}
macro_rules! impl_primitive {
($t:ty) => {
impl Binary for $t {
type Rhs = $t ;
fn into_rhs(&self) -> &Self::Rhs { self }
}
impl AddIdentity for $t {
fn add_id() -> $t { 0 }
}
impl MulIdentity for $t {
fn mul_id() -> $t { 1 }
}
};
($t:ty, $($ts:ty),*) => {
implement!{$t, [
AddAssociative,
MulAssociative,
AddCommutative,
MulCommutative,
AddMulDistributive,
]}
impl_primitive!{$t}
impl_primitive!{$($ts),*}
};
}
impl_primitive! {
i8, i16, i32, i64, i128, isize,
u8, u16, u32, u64, u128, usize
}
impl Binary for String {
type Rhs = str;
fn into_rhs(&self) -> &str {
&self
}
}
implement! {String, [AddAssociative,]}
impl AddIdentity for String {
fn add_id() -> Self {
"".into()
}
fn is_add_id(&self) -> bool {
self.is_empty()
}
}
pub use chalk_proc_macro::chalk;