-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactor traits into an independent crate.
This change refactors adjunct and geometric traits into the Eudoxus crate. Eudoxus provides essential traits and implementations for primitives and other foreign types. Theon now depends on Eudoxus and re-exports these traits while providing additional types and APIs. Theon remains the primary crate and API. Because rich sets of traits are infectious, Eudoxus is meant to change very infrequently while Theon can change without invalidating any foreign trait implementations. Theon can also provide APIs with richer type constraints including traits from various crates in the ecosystem.
- Loading branch information
1 parent
74ffd82
commit 8ad482c
Showing
19 changed files
with
1,332 additions
and
791 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,59 +1,5 @@ | ||
[package] | ||
name = "theon" | ||
description = "Abstraction of Euclidean spaces." | ||
keywords = ["geometry", "graphics", "math"] | ||
version = "0.0.1" | ||
authors = ["Sean Olson <[email protected]>"] | ||
edition = "2018" | ||
license = "MIT" | ||
readme = "README.md" | ||
repository = "https://github.com/olson-sean-k/theon" | ||
|
||
[package.metadata.docs.rs] | ||
default-target = "x86_64-unknown-linux-gnu" | ||
# Enable all features so that trait implementations for types from commonly used | ||
# crates are shown. | ||
all-features = true | ||
# Enable KaTex support. | ||
rustdoc-args = [ | ||
"--html-in-header", | ||
"doc/katex-header.html", | ||
[workspace] | ||
members = [ | ||
"eudoxus", | ||
"theon" | ||
] | ||
|
||
[features] | ||
default = ["geometry-nalgebra"] | ||
geometry-cgmath = ["cgmath"] | ||
geometry-glam = ["glam"] | ||
geometry-mint = ["mint"] | ||
geometry-nalgebra = ["nalgebra"] | ||
geometry-ultraviolet = ["ultraviolet"] | ||
lapack = ["ndarray", "ndarray-linalg"] | ||
|
||
[dependencies] | ||
approx = "^0.3.0" | ||
arrayvec = "^0.5.1" | ||
decorum = "^0.3.0" | ||
itertools = "^0.9.0" | ||
num = "^0.3.0" | ||
typenum = "^1.10.0" | ||
|
||
cgmath = { version = "^0.17.0", optional = true } | ||
glam = { version = "^0.9.0", optional = true } | ||
mint = { version = "^0.5.0", optional = true } | ||
nalgebra = { version = "^0.22.0", optional = true } | ||
ultraviolet = { version = "^0.6.0", optional = true } | ||
|
||
[target.'cfg(target_os = "linux")'.dependencies.ndarray] | ||
version = "^0.13.0" | ||
optional = true | ||
|
||
# LAPACK packages are difficult to distribute. MKL appears to build reliably on | ||
# Linux, but does not support Windows and yields strange results on MacOS. The | ||
# other supported packages require a more complex build environment. | ||
[target.'cfg(target_os = "linux")'.dependencies.ndarray-linalg] | ||
version = "^0.12.0" | ||
features = ["intel-mkl"] | ||
optional = true | ||
|
||
[dev-dependencies] | ||
nalgebra = "^0.22.0" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
[package] | ||
name = "eudoxus" | ||
description = "Abstraction of Euclidean spaces." | ||
keywords = ["geometry", "graphics", "math"] | ||
version = "0.0.1" | ||
authors = ["Sean Olson <[email protected]>"] | ||
edition = "2018" | ||
license = "MIT" | ||
readme = "../README.md" | ||
repository = "https://github.com/olson-sean-k/theon" | ||
|
||
[package.metadata.docs.rs] | ||
default-target = "x86_64-unknown-linux-gnu" | ||
# Enable all features so that trait implementations for types from commonly used | ||
# crates are shown. | ||
all-features = true | ||
# Enable KaTex support. | ||
rustdoc-args = [ | ||
"--html-in-header", | ||
"doc/katex-header.html", | ||
] | ||
|
||
[features] | ||
default = [] | ||
geometry-cgmath = ["cgmath"] | ||
geometry-glam = ["glam"] | ||
geometry-mint = ["mint"] | ||
geometry-nalgebra = ["nalgebra"] | ||
geometry-ultraviolet = ["ultraviolet"] | ||
|
||
[dependencies] | ||
num-traits = "^0.2.0" | ||
typenum = "^1.13.0" | ||
|
||
# Integrations. | ||
cgmath = { version = "=0.18.0", optional = true } | ||
glam = { version = "=0.17.1", optional = true } | ||
mint = { version = "=0.5.6", optional = true } | ||
nalgebra = { version = "=0.28.0", optional = true } | ||
ultraviolet = { version = "=0.8.1", optional = true } | ||
|
||
[dev-dependencies] | ||
nalgebra = "^0.22.0" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,183 @@ | ||
//! Homogeneous structured data. | ||
//! | ||
//! This module provides traits that abstract over structured homogeneous data. | ||
//! In particular, these traits are implemented by array-like types with some | ||
//! number of structured homogeneous elements. Here, _structure_ refers to | ||
//! layout and ordering. A type that implements these traits is known as an | ||
//! _adjunct_ and must implement the most basic `Adjunct` trait. | ||
//! | ||
//! Adjunct traits mirror iterator operations but act on both bounded and | ||
//! unbounded data. Eudoxus uses these traits to manipulate data structures that | ||
//! describe geometric constructs, typically as a matrix of scalar values. | ||
//! Adjuncts can be both simple `struct`s with well-defined fields and more | ||
//! dynamic types like `Vec`s. | ||
//! | ||
//! Implementations for adjunct traits are provided for integrated foreign types | ||
//! when enabling geometry features. For example, implementations of `Adjunct` | ||
//! and other traits are provided for `nalgebra` types when the | ||
//! `geometry-nalgebra` feature is enabled. See the `integration` module. | ||
use num_traits::{One, Zero}; | ||
use std::ops::{Add, Mul}; | ||
|
||
use crate::space::{FiniteDimensional, ProjectiveDimensions}; | ||
use crate::Increment; | ||
|
||
pub trait Adjunct: Sized { | ||
type Item; | ||
} | ||
|
||
pub trait Linear: Adjunct { | ||
fn get(&self, index: usize) -> Option<&Self::Item>; | ||
} | ||
|
||
pub trait Converged: Adjunct { | ||
fn converged(value: Self::Item) -> Self; | ||
} | ||
|
||
pub trait Map<T = <Self as Adjunct>::Item>: Adjunct { | ||
type Output: Adjunct<Item = T>; | ||
|
||
fn map<F>(self, f: F) -> Self::Output | ||
where | ||
F: FnMut(Self::Item) -> T; | ||
} | ||
|
||
pub trait ZipMap<T = <Self as Adjunct>::Item>: Adjunct { | ||
type Output: Adjunct<Item = T>; | ||
|
||
fn zip_map<F>(self, other: Self, f: F) -> Self::Output | ||
where | ||
F: FnMut(Self::Item, Self::Item) -> T; | ||
|
||
fn per_item_sum(self, other: Self) -> Self::Output | ||
where | ||
Self: Adjunct<Item = T>, | ||
T: Add<Output = T>, | ||
{ | ||
self.zip_map(other, |a, b| a + b) | ||
} | ||
|
||
fn per_item_product(self, other: Self) -> Self::Output | ||
where | ||
Self: Adjunct<Item = T>, | ||
T: Mul<Output = T>, | ||
{ | ||
self.zip_map(other, |a, b| a * b) | ||
} | ||
} | ||
|
||
pub trait Fold: Adjunct { | ||
fn fold<T, F>(self, seed: T, f: F) -> T | ||
where | ||
F: FnMut(T, Self::Item) -> T; | ||
|
||
fn sum(self) -> Self::Item | ||
where | ||
Self::Item: Add<Output = Self::Item> + Zero, | ||
{ | ||
self.fold(Zero::zero(), |sum, n| sum + n) | ||
} | ||
|
||
fn product(self) -> Self::Item | ||
where | ||
Self::Item: Mul<Output = Self::Item> + One, | ||
{ | ||
self.fold(One::one(), |product, n| product * n) | ||
} | ||
|
||
fn any<F>(self, mut f: F) -> bool | ||
where | ||
F: FnMut(Self::Item) -> bool, | ||
{ | ||
self.fold(false, |sum, item| { | ||
if sum { | ||
sum | ||
} | ||
else { | ||
f(item) | ||
} | ||
}) | ||
} | ||
|
||
fn all<F>(self, mut f: F) -> bool | ||
where | ||
F: FnMut(Self::Item) -> bool, | ||
{ | ||
self.fold(true, |sum, item| { | ||
if sum { | ||
f(item) | ||
} | ||
else { | ||
sum | ||
} | ||
}) | ||
} | ||
} | ||
|
||
// NOTE: This trait uses an input parameter `S` instead of an associated type | ||
// `Output`, because some types can be reasonably truncated into various | ||
// types. For example, the `glam` crate provides several vector | ||
// representations, and its `Vec3` and `Vec3A` types both extend into and | ||
// truncate from the `Vec4` type. | ||
pub trait TruncateInto<S>: FiniteDimensional<N = ProjectiveDimensions<S>> | ||
where | ||
S: Adjunct<Item = Self::Item> + FiniteDimensional, | ||
S::N: Increment, | ||
{ | ||
fn truncate(self) -> (S, Self::Item); | ||
} | ||
|
||
// NOTE: This trait uses an input parameter `S` instead of an associated type | ||
// `Output`, because some types can be reasonably extended into various | ||
// types. For example, the `glam` crate provides several vector | ||
// representations, and its `Vec3` and `Vec3A` types both extend into and | ||
// truncate from the `Vec4` type. | ||
pub trait ExtendInto<S>: FiniteDimensional | ||
where | ||
S: Adjunct<Item = Self::Item> + FiniteDimensional<N = ProjectiveDimensions<Self>>, | ||
Self::N: Increment, | ||
{ | ||
fn extend(self, item: Self::Item) -> S; | ||
} | ||
|
||
pub trait TryFromIterator<I>: Linear | ||
where | ||
I: Iterator<Item = Self::Item>, | ||
{ | ||
type Error; | ||
type Remainder: Iterator<Item = I::Item>; | ||
|
||
fn try_from_iter(items: I) -> Result<(Self, Option<Self::Remainder>), Self::Error>; | ||
} | ||
|
||
pub trait IntoIterator: Linear { | ||
type Output: Iterator<Item = Self::Item>; | ||
|
||
fn into_iter(self) -> Self::Output; | ||
} | ||
|
||
pub trait IteratorExt: Iterator + Sized { | ||
fn try_collect<T>(self) -> Result<(T, Option<T::Remainder>), T::Error> | ||
where | ||
T: TryFromIterator<Self, Item = Self::Item>, | ||
{ | ||
T::try_from_iter(self) | ||
} | ||
|
||
// TODO: Move this into Theon. | ||
fn try_collect_all<T>(self) -> Result<T, ()> | ||
where | ||
T: TryFromIterator<Self, Item = Self::Item>, | ||
{ | ||
let (collection, remainder) = self.try_collect::<T>().map_err(|_| ())?; | ||
if remainder.is_some() { | ||
Err(()) | ||
} | ||
else { | ||
Ok(collection) | ||
} | ||
} | ||
} | ||
|
||
impl<I> IteratorExt for I where I: Iterator + Sized {} |
Oops, something went wrong.