expressions/
expressions.rsuse orx_imp_vec::*;
use std::{
fmt::Display,
ops::{Add, Sub},
};
#[derive(Default)]
struct Scope<'a> {
expressions: ImpVec<Expr<'a>>,
}
impl<'a> Scope<'a> {
fn symbol(&'a self, name: &'static str) -> ExprInScope<'a> {
let expr = Expr::Symbol(name);
self.expressions.imp_push(expr);
ExprInScope {
scope: self,
expr: &self.expressions[self.expressions.len() - 1],
}
}
}
enum Expr<'a> {
Symbol(&'static str),
Addition(&'a Expr<'a>, &'a Expr<'a>),
Subtraction(&'a Expr<'a>, &'a Expr<'a>),
}
impl<'a> Display for Expr<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Expr::Symbol(x) => write!(f, "{}", x),
Expr::Addition(x, y) => write!(f, "{} + {}", x, y),
Expr::Subtraction(x, y) => write!(f, "{} - {}", x, y),
}
}
}
#[derive(Clone, Copy)]
struct ExprInScope<'a> {
scope: &'a Scope<'a>,
expr: &'a Expr<'a>,
}
impl<'a> ExprInScope<'a> {
fn belongs_to_same_scope(&self, other: Self) -> bool {
let self_scope = self.scope as *const Scope;
let other_scope = other.scope as *const Scope;
self_scope == other_scope
}
}
impl<'a> Display for ExprInScope<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.expr)
}
}
impl<'a> Add for ExprInScope<'a> {
type Output = ExprInScope<'a>;
fn add(self, rhs: Self) -> Self::Output {
assert!(self.belongs_to_same_scope(rhs));
let expressions = &self.scope.expressions;
let expr = Expr::Addition(self.expr, rhs.expr);
expressions.imp_push(expr);
ExprInScope {
scope: self.scope,
expr: &expressions[expressions.len() - 1],
}
}
}
impl<'a> Sub for ExprInScope<'a> {
type Output = ExprInScope<'a>;
fn sub(self, rhs: Self) -> Self::Output {
assert!(self.belongs_to_same_scope(rhs));
let expressions = &self.scope.expressions;
let expr = Expr::Subtraction(self.expr, rhs.expr);
expressions.imp_push(expr);
ExprInScope {
scope: self.scope,
expr: &expressions[expressions.len() - 1],
}
}
}
fn main() {
let scope = Scope::default();
let x = scope.symbol("x");
let y = scope.symbol("y");
assert_eq!(&x.to_string(), "x");
assert_eq!(&y.to_string(), "y");
let p = x + y;
assert_eq!(&p.to_string(), "x + y");
let q = x - y;
assert_eq!(&q.to_string(), "x - y");
let t = p + q;
assert_eq!(&t.to_string(), "x + y + x - y");
let all_expressions: Vec<_> = scope.expressions.iter().map(|x| x.to_string()).collect();
assert_eq!(
all_expressions,
["x", "y", "x + y", "x - y", "x + y + x - y"]
);
}