Skip to content

Instantly share code, notes, and snippets.

@Geal
Created April 8, 2019 17:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Geal/12a9e77291553cd5da64f6bab6315497 to your computer and use it in GitHub Desktop.
Save Geal/12a9e77291553cd5da64f6bab6315497 to your computer and use it in GitHub Desktop.
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)
}
}
#![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();
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment