Skip to content

Instantly share code, notes, and snippets.

@rust-play
Created February 28, 2022 12:16
Show Gist options
  • Save rust-play/a050229041bd8924c1891ab4756827d7 to your computer and use it in GitHub Desktop.
Save rust-play/a050229041bd8924c1891ab4756827d7 to your computer and use it in GitHub Desktop.
Code shared from the Rust Playground
use std::borrow::Cow;
use std::ops::Deref;
pub enum Value<'a> {
Int(i32),
Str(Cow<'a, str>),
}
pub struct ExecutionContext<'e> {
value: Option<Value<'e>>,
}
trait HasExecutionContext<'a> {
type ExecutionContext: Deref<Target = ExecutionContext<'a>> + 'a;
}
type ExecutionContextOf<'a, T> = <T as HasExecutionContext<'a>>::ExecutionContext;
trait BooleanOperationWithGat: for<'a> HasExecutionContext<'a> {
fn execute<'e>(&self, ctx: ExecutionContextOf<'e, Self>) -> bool;
}
trait ValueOperationWithGat: for<'a> HasExecutionContext<'a> {
fn execute<'e: 'e>(&self, ctx: ExecutionContextOf<'e, Self>) -> Value<'e>;
}
enum ValueExpr {
Value,
FunctionCall(FunctionCallExpr),
}
enum ComparisonExpr {
StrEq { lhs: ValueExpr, rhs: String },
}
enum FunctionCallExpr {
Lowercase,
}
trait Compiler: for<'a> HasExecutionContext<'a> {
type BooleanOperation: BooleanOperationWithGat
+ for<'a> HasExecutionContext<'a, ExecutionContext = ExecutionContextOf<'a, Self>>;
type ValueOperation: ValueOperationWithGat
+ for<'a> HasExecutionContext<'a, ExecutionContext = ExecutionContextOf<'a, Self>>;
fn compile_comparison_expr(
&mut self,
comparison_expr: ComparisonExpr,
) -> Self::BooleanOperation;
fn compile_function_call_expr(
&mut self,
function_call_expr: FunctionCallExpr,
) -> Self::ValueOperation;
}
impl<'a> HasExecutionContext<'a> for Box<dyn for<'e> Fn(&'e ExecutionContext<'e>) -> bool> {
type ExecutionContext = &'a ExecutionContext<'a>;
}
impl BooleanOperationWithGat for Box<dyn for<'e> Fn(&'e ExecutionContext<'e>) -> bool> {
#[inline]
fn execute<'e>(&self, ctx: ExecutionContextOf<'e, Self>) -> bool {
(self)(ctx)
}
}
impl<'a> HasExecutionContext<'a> for Box<dyn for<'e> Fn(&'e ExecutionContext<'e>) -> Value<'e>> {
type ExecutionContext = &'a ExecutionContext<'a>;
}
impl ValueOperationWithGat for Box<dyn for<'e> Fn(&'e ExecutionContext<'e>) -> Value<'e>> {
#[inline]
// the 'e: 'e works around a compiler bug
fn execute<'e: 'e>(&self, ctx: ExecutionContextOf<'e, Self>) -> Value<'e> {
(self)(ctx)
}
}
struct DefaultCompiler;
impl<'a> HasExecutionContext<'a> for DefaultCompiler {
type ExecutionContext = &'a ExecutionContext<'a>;
}
impl Compiler for DefaultCompiler {
type BooleanOperation = Box<dyn for<'e> Fn(&'e ExecutionContext<'e>) -> bool>;
type ValueOperation = Box<dyn for<'e> Fn(&'e ExecutionContext<'e>) -> Value<'e>>;
fn compile_comparison_expr(
&mut self,
comparison_expr: ComparisonExpr,
) -> Self::BooleanOperation {
match comparison_expr {
ComparisonExpr::StrEq { lhs, rhs } => {
match lhs {
ValueExpr::Value => Box::new(move |ctx: &ExecutionContext<'_>| {
match ctx.value.as_ref().unwrap() {
Value::Str(left) => &rhs == left,
Value::Int(_) => unreachable!(),
}
}),
ValueExpr::FunctionCall(function_call_expr) => {
let call = self.compile_function_call_expr(function_call_expr);
Box::new(move |ctx: &ExecutionContext<'_>| match call.execute(ctx) {
Value::Str(left) => &rhs == &left,
Value::Int(_) => unreachable!(),
})
}
}
}
}
}
fn compile_function_call_expr(
&mut self,
function_call_expr: FunctionCallExpr,
) -> Self::ValueOperation {
match function_call_expr {
FunctionCallExpr::Lowercase => {
Box::new(
move |ctx: &ExecutionContext<'_>| match ctx.value.as_ref().unwrap() {
Value::Str(left) => Value::Str(left.to_ascii_lowercase().into()),
Value::Int(_) => unreachable!(),
},
)
}
}
}
}
fn main() {
let comp = ComparisonExpr::StrEq {
lhs: ValueExpr::FunctionCall(FunctionCallExpr::Lowercase),
rhs: String::from("test"),
};
let mut compiler = DefaultCompiler;
let pred = compiler.compile_comparison_expr(comp);
let ctx = ExecutionContext {
value: Some(Value::Str("Test".into())),
};
println!("{}", pred.execute(&ctx));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment