use std::iter::FusedIterator;
use std::ops::{Deref, Index};
use std::slice::ChunksExact;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SimpleUnary<'a> {
pub op: &'a str,
arg: Box<Simple<'a>>,
}
impl<'a> SimpleUnary<'a> {
pub fn new<S>(op: &'a str, arg: S) -> Self
where
S: Into<Simple<'a>>,
{
SimpleUnary {
op,
arg: Box::new(arg.into()),
}
}
#[must_use]
pub fn arg(&self) -> &Simple<'a> {
&self.arg
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SimpleFunc<'a> {
pub func: &'a str,
arg: Box<Simple<'a>>,
}
impl<'a> SimpleFunc<'a> {
pub fn new<S>(func: &'a str, arg: S) -> Self
where
S: Into<Simple<'a>>,
{
SimpleFunc {
func,
arg: Box::new(arg.into()),
}
}
#[must_use]
pub fn arg(&self) -> &Simple<'a> {
&self.arg
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SimpleBinary<'a> {
pub op: &'a str,
first: Box<Simple<'a>>,
second: Box<Simple<'a>>,
}
impl<'a> SimpleBinary<'a> {
pub fn new<F, S>(op: &'a str, first: F, second: S) -> Self
where
F: Into<Simple<'a>>,
S: Into<Simple<'a>>,
{
SimpleBinary {
op,
first: Box::new(first.into()),
second: Box::new(second.into()),
}
}
#[must_use]
pub fn first(&self) -> &Simple<'a> {
&self.first
}
#[must_use]
pub fn second(&self) -> &Simple<'a> {
&self.second
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Group<'a> {
pub left_bracket: &'a str,
pub expr: Expression<'a>,
pub right_bracket: &'a str,
}
impl<'a> Group<'a> {
pub fn new<E: Into<Expression<'a>>>(
left_bracket: &'a str,
expr: E,
right_bracket: &'a str,
) -> Self {
Group {
left_bracket,
expr: expr.into(),
right_bracket,
}
}
pub fn from_iter<T, I>(left_bracket: &'a str, inters: T, right_bracket: &'a str) -> Self
where
T: IntoIterator<Item = I>,
I: Into<Intermediate<'a>>,
{
Group {
left_bracket,
expr: inters.into_iter().collect(),
right_bracket,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Matrix<'a> {
pub left_bracket: &'a str,
cells: Box<[Expression<'a>]>,
num_cols: usize,
pub right_bracket: &'a str,
}
impl<'a> Matrix<'a> {
pub fn new<E>(left_bracket: &'a str, cells: E, num_cols: usize, right_bracket: &'a str) -> Self
where
E: Into<Box<[Expression<'a>]>>,
{
let cells = cells.into();
assert!(num_cols > 0, "num_cols must be positive");
assert_eq!(cells.len() / num_cols * num_cols, cells.len());
Matrix {
left_bracket,
cells,
num_cols,
right_bracket,
}
}
#[must_use]
pub fn num_cols(&self) -> usize {
self.num_cols
}
#[must_use]
pub fn num_rows(&self) -> usize {
self.cells.len() / self.num_cols
}
#[must_use]
pub fn num_cells(&self) -> usize {
self.cells.len()
}
#[must_use]
pub fn rows(&self) -> MatrixRows<'a, '_> {
MatrixRows(self.cells.chunks_exact(self.num_cols))
}
#[must_use]
pub fn iter(&self) -> MatrixRows<'a, '_> {
self.into_iter()
}
}
impl<'a, 'b> IntoIterator for &'b Matrix<'a> {
type IntoIter = MatrixRows<'a, 'b>;
type Item = &'b [Expression<'a>];
fn into_iter(self) -> Self::IntoIter {
self.rows()
}
}
impl<'a> Index<usize> for Matrix<'a> {
type Output = [Expression<'a>];
fn index(&self, row: usize) -> &Self::Output {
self.rows().nth(row).expect("index out of bounds")
}
}
impl<'a> Index<[usize; 2]> for Matrix<'a> {
type Output = Expression<'a>;
fn index(&self, idx: [usize; 2]) -> &Self::Output {
let [x, y] = idx;
assert!(x < self.num_cols, "index out of bounds");
&self.cells[x + self.num_cols * y]
}
}
#[derive(Debug, Clone)]
pub struct MatrixRows<'a, 'b>(ChunksExact<'b, Expression<'a>>);
impl<'a, 'b> Iterator for MatrixRows<'a, 'b> {
type Item = &'b [Expression<'a>];
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
fn count(self) -> usize {
self.len()
}
fn nth(&mut self, n: usize) -> Option<Self::Item> {
self.0.nth(n)
}
fn last(mut self) -> Option<Self::Item> {
self.next_back()
}
}
impl FusedIterator for MatrixRows<'_, '_> {}
impl DoubleEndedIterator for MatrixRows<'_, '_> {
fn next_back(&mut self) -> Option<Self::Item> {
self.0.next_back()
}
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
self.0.nth_back(n)
}
}
impl ExactSizeIterator for MatrixRows<'_, '_> {}
#[derive(Default, Debug, Clone, PartialEq, Eq)]
pub enum Simple<'a> {
#[default]
Missing,
Number(&'a str),
Text(&'a str),
Ident(&'a str),
Symbol(&'a str),
Unary(SimpleUnary<'a>),
Func(SimpleFunc<'a>),
Binary(SimpleBinary<'a>),
Group(Group<'a>),
Matrix(Matrix<'a>),
}
impl Simple<'_> {
#[must_use]
pub fn as_option(&self) -> Option<&Self> {
match self {
Simple::Missing => None,
simple => Some(simple),
}
}
}
macro_rules! simple_from {
($from:ty => $to:ident) => {
impl<'a> From<$from> for Simple<'a> {
fn from(inp: $from) -> Self {
Simple::$to(inp)
}
}
};
}
simple_from!(SimpleUnary<'a> => Unary);
simple_from!(SimpleFunc<'a> => Func);
simple_from!(SimpleBinary<'a> => Binary);
simple_from!(Group<'a> => Group);
simple_from!(Matrix<'a> => Matrix);
#[derive(Default, Debug, Clone, PartialEq, Eq)]
pub enum Script<'a> {
#[default]
None,
Sub(Simple<'a>),
Super(Simple<'a>),
Subsuper(Simple<'a>, Simple<'a>),
}
impl<'a> Script<'a> {
#[must_use]
pub fn sub(&self) -> Option<&Simple<'a>> {
match self {
Script::Sub(sub) | Script::Subsuper(sub, _) => Some(sub),
_ => None,
}
}
#[must_use]
pub fn sup(&self) -> Option<&Simple<'a>> {
match self {
Script::Super(sup) | Script::Subsuper(_, sup) => Some(sup),
_ => None,
}
}
}
#[derive(Default, Debug, Clone, PartialEq, Eq)]
pub struct SimpleScript<'a> {
pub simple: Simple<'a>,
pub script: Script<'a>,
}
impl<'a> SimpleScript<'a> {
pub fn new<S>(simple: S, script: Script<'a>) -> Self
where
S: Into<Simple<'a>>,
{
SimpleScript {
simple: simple.into(),
script,
}
}
pub fn without_scripts<S>(simple: S) -> Self
where
S: Into<Simple<'a>>,
{
Self::new(simple, Script::None)
}
pub fn with_sub<S, Sub>(simple: S, sub: Sub) -> Self
where
S: Into<Simple<'a>>,
Sub: Into<Simple<'a>>,
{
Self::new(simple, Script::Sub(sub.into()))
}
pub fn with_super<S, Sup>(simple: S, sup: Sup) -> Self
where
S: Into<Simple<'a>>,
Sup: Into<Simple<'a>>,
{
Self::new(simple, Script::Super(sup.into()))
}
pub fn with_subsuper<S, Sub, Sup>(simple: S, sub: Sub, sup: Sup) -> Self
where
S: Into<Simple<'a>>,
Sub: Into<Simple<'a>>,
Sup: Into<Simple<'a>>,
{
Self::new(simple, Script::Subsuper(sub.into(), sup.into()))
}
}
impl<'a, S> From<S> for SimpleScript<'a>
where
S: Into<Simple<'a>>,
{
fn from(inp: S) -> Self {
SimpleScript::without_scripts(inp.into())
}
}
impl<'a> Deref for SimpleScript<'a> {
type Target = Script<'a>;
fn deref(&self) -> &Self::Target {
&self.script
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Func<'a> {
pub func: &'a str,
pub script: Script<'a>,
arg: Box<ScriptFunc<'a>>,
}
impl<'a> Func<'a> {
pub fn new<Arg>(func: &'a str, script: Script<'a>, arg: Arg) -> Self
where
Arg: Into<ScriptFunc<'a>>,
{
Func {
func,
script,
arg: Box::new(arg.into()),
}
}
pub fn without_scripts<Arg>(func: &'a str, arg: Arg) -> Self
where
Arg: Into<ScriptFunc<'a>>,
{
Self::new(func, Script::None, arg)
}
pub fn with_sub<Sub, Arg>(func: &'a str, sub: Sub, arg: Arg) -> Self
where
Sub: Into<Simple<'a>>,
Arg: Into<ScriptFunc<'a>>,
{
Self::new(func, Script::Sub(sub.into()), arg)
}
pub fn with_super<Sup, Arg>(func: &'a str, sup: Sup, arg: Arg) -> Self
where
Sup: Into<Simple<'a>>,
Arg: Into<ScriptFunc<'a>>,
{
Self::new(func, Script::Super(sup.into()), arg)
}
pub fn with_subsuper<Sub, Sup, Arg>(func: &'a str, sub: Sub, sup: Sup, arg: Arg) -> Self
where
Sub: Into<Simple<'a>>,
Sup: Into<Simple<'a>>,
Arg: Into<ScriptFunc<'a>>,
{
Self::new(func, Script::Subsuper(sub.into(), sup.into()), arg)
}
#[must_use]
pub fn arg(&self) -> &ScriptFunc<'a> {
&self.arg
}
}
impl<'a> Deref for Func<'a> {
type Target = Script<'a>;
fn deref(&self) -> &Self::Target {
&self.script
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ScriptFunc<'a> {
Simple(SimpleScript<'a>),
Func(Func<'a>),
}
impl Default for ScriptFunc<'_> {
fn default() -> Self {
ScriptFunc::Simple(SimpleScript::default())
}
}
impl<'a> From<Func<'a>> for ScriptFunc<'a> {
fn from(func: Func<'a>) -> Self {
ScriptFunc::Func(func)
}
}
impl<'a, S> From<S> for ScriptFunc<'a>
where
S: Into<SimpleScript<'a>>,
{
fn from(inp: S) -> Self {
ScriptFunc::Simple(inp.into())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Frac<'a> {
pub numer: ScriptFunc<'a>,
pub denom: ScriptFunc<'a>,
}
impl<'a> Frac<'a> {
pub fn new<N, D>(numer: N, denom: D) -> Self
where
N: Into<ScriptFunc<'a>>,
D: Into<ScriptFunc<'a>>,
{
Frac {
numer: numer.into(),
denom: denom.into(),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Intermediate<'a> {
ScriptFunc(ScriptFunc<'a>),
Frac(Frac<'a>),
}
impl Default for Intermediate<'_> {
fn default() -> Self {
Intermediate::ScriptFunc(ScriptFunc::default())
}
}
impl<'a> From<Frac<'a>> for Intermediate<'a> {
fn from(frac: Frac<'a>) -> Self {
Intermediate::Frac(frac)
}
}
impl<'a, S> From<S> for Intermediate<'a>
where
S: Into<ScriptFunc<'a>>,
{
fn from(inp: S) -> Self {
Intermediate::ScriptFunc(inp.into())
}
}
#[derive(Default, Debug, Clone, PartialEq, Eq)]
pub struct Expression<'a>(Box<[Intermediate<'a>]>);
impl<'a> Deref for Expression<'a> {
type Target = [Intermediate<'a>];
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<'a, I> FromIterator<I> for Expression<'a>
where
I: Into<Intermediate<'a>>,
{
fn from_iter<T>(iter: T) -> Self
where
T: IntoIterator<Item = I>,
{
Expression(iter.into_iter().map(std::convert::Into::into).collect())
}
}
impl<'a, B> From<B> for Expression<'a>
where
B: Into<Box<[Intermediate<'a>]>>,
{
fn from(inp: B) -> Self {
Expression(inp.into())
}
}
#[cfg(test)]
mod tests {
use super::{
Expression, Frac, Func, Group, Intermediate, Matrix, Script, ScriptFunc, Simple,
SimpleBinary, SimpleFunc, SimpleScript, SimpleUnary,
};
#[test]
fn simple_unary() {
let unary = SimpleUnary::new("sqrt", Simple::Ident("x"));
assert_eq!(unary.op, "sqrt");
assert_eq!(unary.arg(), &Simple::Ident("x"));
assert_eq!(
Simple::from(unary),
Simple::Unary(SimpleUnary::new("sqrt", Simple::Ident("x")))
);
}
#[test]
fn simple_func() {
let func = SimpleFunc::new("sin", Simple::Ident("x"));
assert_eq!(func.func, "sin");
assert_eq!(func.arg(), &Simple::Ident("x"));
assert_eq!(
Simple::from(func),
Simple::Func(SimpleFunc::new("sin", Simple::Ident("x")))
);
}
#[test]
fn simple_binary() {
let binary = SimpleBinary::new("root", Simple::Number("3"), Simple::Ident("x"));
assert_eq!(binary.op, "root");
assert_eq!(binary.first(), &Simple::Number("3"));
assert_eq!(binary.second(), &Simple::Ident("x"));
assert_eq!(
Simple::from(binary),
Simple::Binary(SimpleBinary::new(
"root",
Simple::Number("3"),
Simple::Ident("x")
)),
);
}
#[test]
fn group() {
let from_expr = Group::new("(", Expression::from_iter([Simple::Ident("x")]), ")");
let from_inters = Group::from_iter("(", [Simple::Ident("x")], ")");
assert_eq!(from_expr, from_inters);
assert_eq!(from_expr.left_bracket, "(");
assert_eq!(from_expr.right_bracket, ")");
assert_eq!(from_expr.expr.len(), 1);
assert_eq!(Simple::from(from_expr.clone()), Simple::Group(from_expr));
}
fn cell(ident: &str) -> Expression<'_> {
Expression::from_iter([Simple::Ident(ident)])
}
#[test]
fn matrix() {
let matrix = Matrix::new("[", [cell("a"), cell("b"), cell("c"), cell("d")], 2, "]");
assert_eq!(matrix.left_bracket, "[");
assert_eq!(matrix.right_bracket, "]");
assert_eq!(matrix.num_cols(), 2);
assert_eq!(matrix.num_rows(), 2);
assert_eq!(matrix.num_cells(), 4);
let rows: Vec<_> = matrix.rows().collect();
assert_eq!(rows, [[cell("a"), cell("b")], [cell("c"), cell("d")]]);
assert_eq!(matrix.iter().count(), 2);
assert_eq!((&matrix).into_iter().count(), 2);
assert_eq!(matrix[0], [cell("a"), cell("b")]);
assert_eq!(matrix[1], [cell("c"), cell("d")]);
assert_eq!(matrix[[0, 0]], cell("a"));
assert_eq!(matrix[[1, 0]], cell("b"));
assert_eq!(matrix[[0, 1]], cell("c"));
assert_eq!(matrix[[1, 1]], cell("d"));
assert_eq!(Simple::from(matrix.clone()), Simple::Matrix(matrix));
}
#[test]
#[should_panic(expected = "index out of bounds")]
fn matrix_row_out_of_bounds() {
let matrix = Matrix::new("[", [cell("a"), cell("b")], 2, "]");
let _ = &matrix[1];
}
#[test]
#[should_panic(expected = "index out of bounds")]
fn matrix_col_out_of_bounds() {
let matrix = Matrix::new("[", [cell("a"), cell("b")], 2, "]");
let _ = &matrix[[2, 0]];
}
#[test]
#[should_panic(expected = "assertion")]
fn matrix_ragged() {
let _ = Matrix::new("[", [cell("a"), cell("b"), cell("c")], 2, "]");
}
#[test]
#[should_panic(expected = "num_cols must be positive")]
fn matrix_zero_cols() {
let _ = Matrix::new("[", [], 0, "]");
}
#[test]
fn matrix_rows_iterator() {
let matrix = Matrix::new("[", [cell("a"), cell("b"), cell("c"), cell("d")], 1, "]");
assert_eq!(matrix.rows().len(), 4);
assert_eq!(matrix.rows().size_hint(), (4, Some(4)));
assert_eq!(matrix.rows().nth(2), Some(&[cell("c")][..]));
assert_eq!(matrix.rows().last(), Some(&[cell("d")][..]));
let mut back = matrix.rows();
assert_eq!(back.next_back(), Some(&[cell("d")][..]));
assert_eq!(back.nth_back(1), Some(&[cell("b")][..]));
}
#[test]
fn simple_as_option() {
assert_eq!(Simple::Missing.as_option(), None);
assert_eq!(Simple::Ident("x").as_option(), Some(&Simple::Ident("x")));
assert_eq!(Simple::default(), Simple::Missing);
}
#[test]
fn script_accessors() {
assert_eq!(Script::default(), Script::None);
assert_eq!(Script::<'_>::None.sub(), None);
assert_eq!(Script::<'_>::None.sup(), None);
let sub = Script::Sub(Simple::Ident("i"));
assert_eq!(sub.sub(), Some(&Simple::Ident("i")));
assert_eq!(sub.sup(), None);
let sup = Script::Super(Simple::Number("2"));
assert_eq!(sup.sub(), None);
assert_eq!(sup.sup(), Some(&Simple::Number("2")));
let both = Script::Subsuper(Simple::Ident("i"), Simple::Number("2"));
assert_eq!(both.sub(), Some(&Simple::Ident("i")));
assert_eq!(both.sup(), Some(&Simple::Number("2")));
}
#[test]
fn simple_script() {
let none = SimpleScript::without_scripts(Simple::Ident("x"));
assert_eq!(none.simple, Simple::Ident("x"));
assert_eq!(none.sub(), None);
assert_eq!(none.sup(), None);
assert_eq!(SimpleScript::default().simple, Simple::Missing);
let sub = SimpleScript::with_sub(Simple::Ident("x"), Simple::Ident("i"));
assert_eq!(sub.sub(), Some(&Simple::Ident("i")));
let sup = SimpleScript::with_super(Simple::Ident("x"), Simple::Number("2"));
assert_eq!(sup.sup(), Some(&Simple::Number("2")));
let both = SimpleScript::with_subsuper(
Simple::Ident("x"),
Simple::Ident("i"),
Simple::Number("2"),
);
assert_eq!(both.sub(), Some(&Simple::Ident("i")));
assert_eq!(both.sup(), Some(&Simple::Number("2")));
assert_eq!(SimpleScript::from(Simple::Ident("x")), none);
}
#[test]
fn func() {
let none = Func::without_scripts("sum", Simple::Ident("x"));
assert_eq!(none.func, "sum");
assert_eq!(none.arg(), &ScriptFunc::from(Simple::Ident("x")));
assert_eq!(none.sub(), None);
let sub = Func::with_sub("sum", Simple::Ident("i"), Simple::Ident("x"));
assert_eq!(sub.sub(), Some(&Simple::Ident("i")));
let sup = Func::with_super("sum", Simple::Number("n"), Simple::Ident("x"));
assert_eq!(sup.sup(), Some(&Simple::Number("n")));
let both = Func::with_subsuper(
"sum",
Simple::Ident("i"),
Simple::Number("n"),
Simple::Ident("x"),
);
assert_eq!(both.sub(), Some(&Simple::Ident("i")));
assert_eq!(both.sup(), Some(&Simple::Number("n")));
}
#[test]
fn script_func() {
let from_func = ScriptFunc::from(Func::without_scripts("sum", Simple::Ident("x")));
assert!(matches!(from_func, ScriptFunc::Func(_)));
let from_simple = ScriptFunc::from(Simple::Ident("x"));
assert!(matches!(from_simple, ScriptFunc::Simple(_)));
assert_eq!(
ScriptFunc::default(),
ScriptFunc::Simple(SimpleScript::default())
);
}
#[test]
fn frac_and_intermediate() {
let frac = Frac::new(Simple::Number("1"), Simple::Number("2"));
assert_eq!(frac.numer, ScriptFunc::from(Simple::Number("1")));
assert_eq!(frac.denom, ScriptFunc::from(Simple::Number("2")));
assert_eq!(Intermediate::from(frac.clone()), Intermediate::Frac(frac));
assert!(matches!(
Intermediate::from(Simple::Ident("x")),
Intermediate::ScriptFunc(_)
));
assert!(matches!(
Intermediate::default(),
Intermediate::ScriptFunc(_)
));
}
#[test]
fn expression() {
let expr = Expression::from_iter([Simple::Ident("x"), Simple::Ident("y")]);
assert_eq!(expr.len(), 2);
assert_eq!(expr[0], Intermediate::from(Simple::Ident("x")));
assert_eq!(Expression::default().len(), 0);
let boxed: Box<[Intermediate<'_>]> = Box::new([Intermediate::from(Simple::Ident("x"))]);
assert_eq!(Expression::from(boxed).len(), 1);
}
}