Skip to content

Instantly share code, notes, and snippets.

@Geal
Created April 8, 2019 17:51
Show Gist options
  • Save Geal/12a9e77291553cd5da64f6bab6315497 to your computer and use it in GitHub Desktop.
Save Geal/12a9e77291553cd5da64f6bab6315497 to your computer and use it in GitHub Desktop.

Revisions

  1. Geal created this gist Apr 8, 2019.
    106 changes: 106 additions & 0 deletions combinators.rs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,106 @@
    use gen::GenError;

    pub trait SerializeFn<I>: Fn(I) -> Result<I, GenError> {}

    impl<I, F: Fn(I) ->Result<I, GenError>> SerializeFn<I> for F {}


    pub fn slice<'a, S: 'a + AsRef<[u8]>>(data: S) -> impl SerializeFn<&'a mut [u8]> {
    let len = data.as_ref().len();

    move |out: &'a mut [u8]| {
    if out.len() < len {
    Err(GenError::BufferTooSmall(len))
    } else {
    (&mut out[..len]).copy_from_slice(data.as_ref());
    Ok(&mut out[len..])
    }
    }
    }


    pub fn string<'a, S: 'a+AsRef<str>>(data: S) -> impl SerializeFn<&'a mut [u8]> {

    let len = data.as_ref().len();
    move |out: &'a mut [u8]| {
    if out.len() < len {
    Err(GenError::BufferTooSmall(len))
    } else {
    (&mut out[..len]).copy_from_slice(data.as_ref().as_bytes());
    Ok(&mut out[len..])
    }
    }
    }

    fn pair<F, G, I>(first: F, second: G) -> impl SerializeFn<I>
    where F: SerializeFn<I>,
    G: SerializeFn<I> {

    move |out: I| {
    let out = first(out)?;
    second(out)
    }
    }

    pub fn separated_list<'w, F, G, I, V>(sep: F, val: G, values: &'w [V]) -> impl SerializeFn<I> + 'w
    where F: SerializeFn<I> + 'w,
    G: Fn(I, &'w V) -> Result<I, GenError> + 'w {
    move |mut out: I| {
    if values.is_empty() {
    Ok(out)
    } else {
    out = val(out, &values[0])?;

    for i in 1..values.len() {
    out = sep(out)?;
    out = val(out, &values[i])?;
    }

    Ok(out)
    }
    }
    }
    /*
    pub fn separated_list2<'a, 'c, 'd, F, G, I, V: 'd, It: Iterator<Item=&'d V>, Arg: Clone+IntoIterator<Item=&'d V, IntoIter=It>>(sep: F, val: G, values: Arg) -> impl SerializeFn<I>
    where F: SerializeFn<I> + 'a,
    G: Fn(I, &'d V) -> Result<I, GenError> + 'c {
    move |mut out: I| {
    let mut it = values.clone().into_iter();
    match it.next() {
    None => return Ok(out),
    Some(first) => {
    out = val(out, &first)?;
    }
    }
    for v in it {
    out = sep(out)?;
    out = val(out, &v)?;
    }
    Ok(out)
    }
    }*/

    pub fn separated_list2<'a, 'b, 'c, F, G, I, It: Iterator<Item=G>, Arg: 'a+Clone+IntoIterator<Item=G, IntoIter=It>>(sep: F, values: Arg) -> impl SerializeFn<I> + 'a
    where F: SerializeFn<I> + 'b + 'a,
    G: SerializeFn<I> + 'c {

    move |mut out: I| {
    let mut it = values.clone().into_iter();
    match it.next() {
    None => return Ok(out),
    Some(first) => {
    out = first(out)?;
    }
    }

    for v in it {
    out = sep(out)?;
    out = v(out)?;
    }

    Ok(out)
    }
    }
    204 changes: 204 additions & 0 deletions json.rs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,204 @@
    #![feature(test)]
    extern crate test;
    #[macro_use]
    extern crate cookie_factory;
    #[macro_use]
    extern crate maplit;

    use std::str;
    use std::collections::BTreeMap;
    use test::Bencher;

    use cookie_factory::*;

    #[derive(Clone, Debug, PartialEq)]
    pub enum JsonValue {
    Str(String),
    Boolean(bool),
    Num(f64),
    Array(Vec<JsonValue>),
    Object(BTreeMap<String, JsonValue>),
    }

    #[inline(always)]
    pub fn gen_str<'a, 'b: 'a>(s: &'b str) -> impl SerializeFn<&'a mut [u8]> {
    move |out: &'a mut [u8]| {
    let out = string("\"")(out)?;
    let out = string(s)(out)?;
    string("\"")(out)
    }
    }

    #[inline(always)]
    pub fn gen_bool<'a>(b: bool) -> impl SerializeFn<&'a mut [u8]> {
    if b {
    string("true")
    } else {
    string("false")
    }
    }

    #[inline(always)]
    pub fn gen_num<'a>(b: f64) -> impl SerializeFn<&'a mut [u8]> {
    /*move |out: &'a mut [u8]| {
    let s = format!("{}", b);
    string(s)(out)
    }*/
    string("1234.56")
    }

    pub fn gen_array<'a, 'b: 'a>(arr: &'b [JsonValue]) -> impl SerializeFn<&'a mut [u8]> {
    move |out: &'a mut [u8]| {
    let out = string("[")(out)?;
    let out = separated_list2(string(","), arr.iter().map(gen_json_value))(out)?;
    string("]")(out)
    }
    }

    pub fn gen_key_value<'a, 'b: 'a>(kv: (&'b String, &'b JsonValue)) -> impl SerializeFn<&'a mut [u8]> {
    move |out: &'a mut [u8]| {
    let out = gen_str(kv.0)(out)?;
    let out = string(":")(out)?;
    gen_json_value(&kv.1)(out)
    }
    }

    pub fn gen_object<'a, 'b: 'a>(o: &'b BTreeMap<String, JsonValue>) -> impl SerializeFn<&'a mut [u8]> {
    move |out: &'a mut [u8]| {
    let out = string("{")(out)?;

    let out = separated_list2(string(","), o.iter().map(gen_key_value))(out)?;
    string("}")(out)
    }
    }


    pub fn gen_json_value<'a>(g: &'a JsonValue) -> impl SerializeFn<&'a mut [u8]> {
    move |out: &'a mut [u8]| {
    match g {
    JsonValue::Str(ref s) => gen_str(s)(out),
    JsonValue::Boolean(ref b) => gen_bool(*b)(out),
    JsonValue::Num(ref n) => gen_num(*n)(out),
    JsonValue::Array(ref v) => gen_array(v)(out),
    JsonValue::Object(ref o) => gen_object(o)(out),
    }
    }
    }

    use std::iter::repeat;

    #[test]
    fn json_test() {
    let value = JsonValue::Object(btreemap!{
    String::from("arr") => JsonValue::Array(vec![JsonValue::Num(1.0), JsonValue::Num(12.3), JsonValue::Num(42.0)]),
    String::from("b") => JsonValue::Boolean(true),
    String::from("o") => JsonValue::Object(btreemap!{
    String::from("x") => JsonValue::Str(String::from("abcd")),
    String::from("y") => JsonValue::Str(String::from("efgh")),
    String::from("empty") => JsonValue::Array(vec![]),
    }),
    });

    let mut buffer = repeat(0).take(16384).collect::<Vec<u8>>();
    let pos = {
    let mut sr = gen_json_value(&value);

    let res = sr(&mut buffer).unwrap();
    res.as_ptr() as usize
    };

    let index = pos - buffer.as_ptr() as usize;


    println!("result:\n{}", str::from_utf8(&buffer[..index]).unwrap());
    assert_eq!(str::from_utf8(&buffer[..index]).unwrap(),
    "{\"arr\":[1234.56,1234.56,1234.56],\"b\":true,\"o\":{\"empty\":[],\"x\":\"abcd\",\"y\":\"efgh\"}}");
    panic!();
    }

    #[bench]
    fn combinators_json(b: &mut Bencher) {
    let element = JsonValue::Object(btreemap!{
    String::from("arr") => JsonValue::Array(vec![JsonValue::Num(1.0), JsonValue::Num(12.3), JsonValue::Num(42.0)]),
    String::from("b") => JsonValue::Boolean(true),
    String::from("o") => JsonValue::Object(btreemap!{
    String::from("x") => JsonValue::Str(String::from("abcd")),
    String::from("y") => JsonValue::Str(String::from("efgh")),
    String::from("empty") => JsonValue::Array(vec![]),
    }),
    });

    let value = JsonValue::Array(repeat(element).take(10).collect::<Vec<JsonValue>>());

    let mut buffer = repeat(0u8).take(16384).collect::<Vec<_>>();
    let pos = {
    let mut sr = gen_json_value(&value);

    let res = sr(&mut buffer).unwrap();
    res.as_ptr() as usize
    };

    let index = pos - buffer.as_ptr() as usize;

    b.bytes = index as u64;
    b.iter(|| {
    let mut sr = gen_json_value(&value);
    let _ = sr(&mut buffer).unwrap();
    });
    }

    #[bench]
    fn combinators_json_create_serializer(b: &mut Bencher) {
    let element = JsonValue::Object(btreemap!{
    String::from("arr") => JsonValue::Array(vec![JsonValue::Num(1.0), JsonValue::Num(12.3), JsonValue::Num(42.0)]),
    String::from("b") => JsonValue::Boolean(true),
    String::from("o") => JsonValue::Object(btreemap!{
    String::from("x") => JsonValue::Str(String::from("abcd")),
    String::from("y") => JsonValue::Str(String::from("efgh")),
    String::from("empty") => JsonValue::Array(vec![]),
    }),
    });

    let value = JsonValue::Array(repeat(element).take(10).collect::<Vec<JsonValue>>());

    b.iter(|| {
    gen_json_value(&value)
    });
    }

    #[bench]
    fn combinators_gen_str_create_serializer(b: &mut Bencher) {
    let mut buffer = repeat(0).take(16384).collect::<Vec<u8>>();
    let pos = {
    let mut sr = gen_str(&"hello");
    let res = sr(&mut buffer).unwrap();

    res.as_ptr() as usize
    };
    let index = pos - buffer.as_ptr() as usize;

    b.bytes = index as u64;
    b.iter(|| {
    gen_str(&"hello")
    });
    }

    #[bench]
    fn combinators_gen_str(b: &mut Bencher) {
    let mut buffer = repeat(0).take(16384).collect::<Vec<u8>>();

    let pos = {
    let mut sr = gen_str(&"hello");

    let res = sr(&mut buffer).unwrap();
    res.as_ptr() as usize
    };

    let index = pos - buffer.as_ptr() as usize;

    b.bytes = index as u64;
    b.iter(|| {
    let mut sr = gen_str(&"hello");
    let _ = sr(&mut buffer).unwrap();
    });
    }