Skip to content

Instantly share code, notes, and snippets.

@d-plaindoux
Last active August 22, 2018 06:23
Show Gist options
  • Save d-plaindoux/99b2ed75533857a03d6b9a837ea8f325 to your computer and use it in GitHub Desktop.
Save d-plaindoux/99b2ed75533857a03d6b9a837ea8f325 to your computer and use it in GitHub Desktop.
Rust example combining structures and trait implementation thanks to generic and type constraints
//---------------------------------------------------------------------------------
// Parser trait type defintion
//---------------------------------------------------------------------------------
trait Parser<E> {}
//---------------------------------------------------------------------------------
// Executable Parsers (Self is constraint)
//---------------------------------------------------------------------------------
pub enum Response<A> {
Success(A, usize, bool),
Reject(usize, bool),
}
pub trait Executable<A> where Self: Parser<A> {
fn execute(&self, s: &str, o: usize) -> Response<A>;
}
//---------------------------------------------------------------------------------
// Any / Single char parser
//---------------------------------------------------------------------------------
pub struct Any();
impl Parser<char> for Any {}
pub fn any() -> Any {
return Any();
}
impl Executable<char> for Any {
fn execute(&self, s: &str, o: usize) -> Response<char> {
if o >= s.len() {
return Response::Reject(o, false);
}
Response::Success(s[o..(o + 1)].chars().next().unwrap(), o + 1, true)
}
}
//---------------------------------------------------------------------------------
// FMap / Functor parser
//---------------------------------------------------------------------------------
pub struct FMap<E, A, B>(E, Box<Fn(A) -> B>) where E: Parser<A>;
impl<E, A, B> Parser<B> for FMap<E, A, B> where E: Parser<A> {}
// Facility
pub trait FMapOperation<E, A, B> where E: Parser<A> {
fn fmap(self, f: Box<(Fn(A) -> B)>) -> FMap<E, A, B>;
}
// fmap behavior facility available for all Parser
impl<E, A, B> FMapOperation<E, A, B> for E where E: Parser<A> {
fn fmap(self, f: Box<(Fn(A) -> B)>) -> FMap<E, A, B> {
FMap(self, f)
}
}
impl<E, A, B> Executable<B> for FMap<E, A, B> where E: Executable<A> + Parser<A> {
fn execute(&self, s: &str, o: usize) -> Response<B> {
let FMap(p, f) = self;
match p.execute(s, o) {
Response::Reject(o, b) => Response::Reject(o, b),
Response::Success(v, o, b) => Response::Success(f(v), o, b)
}
}
}
//---------------------------------------------------------------------------------
// EXAMPLE
//---------------------------------------------------------------------------------
fn main() {
let p = any().fmap(Box::new(|_| 1));
match p.execute("a", 0) {
Response::Reject(_, _) => println!("😞"),
Response::Success(_, _, _) => println!("🤓"),
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment