Skip to content

Commit 85c06cd

Browse files
committed
good progress towards implementing custom derive
1 parent c4b7152 commit 85c06cd

File tree

9 files changed

+334
-17
lines changed

9 files changed

+334
-17
lines changed

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ authors = ["Josh Leverette <coder543@gmail.com>"]
55

66
# uncomment if doing benchmarks
77
# otherwise, it just slows down compilation of examples
8-
# [dev-dependencies]
8+
[dev-dependencies]
9+
zap_derive = { path = "./zap-derive" }
910
# criterion = "0.2.3"
1011
# handlebars = "0.32.0"
1112
# serde_json = "1.0.16"

benches/benchmark.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -126,9 +126,11 @@ impl Runner<PersonNums, PersonStrs, PersonFilters> for Person {
126126

127127
fn filter_str(&self, filter: PersonFilters, _args: &[f64], input: &str, buffer: &mut String) {
128128
match filter {
129-
PersonFilters::ToUpper => for c in input.as_bytes() {
130-
buffer.push(c.to_ascii_uppercase() as char)
131-
},
129+
PersonFilters::ToUpper => {
130+
for c in input.as_bytes() {
131+
buffer.push(c.to_ascii_uppercase() as char)
132+
}
133+
}
132134
_ => unreachable!(),
133135
}
134136
}

examples/derive_example.rs

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
extern crate zap;
2+
3+
#[macro_use]
4+
extern crate zap_derive;
5+
6+
use zap::{compile, Environment, FilterInput, Runner};
7+
8+
use std::io::stdout;
9+
10+
#[derive(Clone, ZapRunner)]
11+
struct Person {
12+
id: u64,
13+
name: String,
14+
age: u32,
15+
weight: f64,
16+
}
17+
18+
#[derive(ZapEnv)]
19+
#[runner = "Person"]
20+
#[filter = "sqrt/0i"]
21+
#[filter = "round/1i"]
22+
#[filter = "toupper/0s"]
23+
struct Provider {
24+
provider: String,
25+
provider_code: u32,
26+
}
27+
28+
fn sqrt(_data: &Person, args: &[f64], input: f64) -> f64 {
29+
input.sqrt()
30+
}
31+
32+
fn round(_data: &Person, args: &[f64], input: f64) -> f64 {
33+
let digits = args[0];
34+
let factor = 10u32.pow(digits as u32) as f64;
35+
let value = (input * factor).round() as f64;
36+
value / factor
37+
}
38+
39+
fn to_upper(_data: &Person, _args: &[f64], input: &str, buffer: &mut String) {
40+
for c in input.as_bytes() {
41+
buffer.push(c.to_ascii_uppercase() as char)
42+
}
43+
}
44+
45+
fn main() {
46+
let template =
47+
"{{provider}} {{provider_code + 4}} {{id}} {{name | toupper}} {{age | sqrt}} {{weight / 2.2 | round 2}}kg\n";
48+
49+
let env = Provider {
50+
provider: "apns".to_string(),
51+
provider_code: 31,
52+
};
53+
54+
let bytecode = match compile(template, &env) {
55+
Ok(bc) => bc,
56+
Err(err) => {
57+
eprintln!("error compiling template: {}", err);
58+
return;
59+
}
60+
};
61+
62+
// println!("bytecode: {:#?}", bytecode);
63+
64+
// build up a group of 100 (similar) people
65+
let mut group = vec![];
66+
for i in 0..100 {
67+
group.push(Person {
68+
id: 12 + i,
69+
name: "Bob".to_string(),
70+
age: 49,
71+
weight: 170.3 + i as f64,
72+
});
73+
}
74+
75+
// reuse these allocations throughout the output process
76+
let mut buffer = String::with_capacity(8);
77+
let mut stack = Vec::with_capacity(8);
78+
let stdout = stdout();
79+
let mut stdout_lock = stdout.lock();
80+
81+
for person in group {
82+
bytecode
83+
.run_with(&person, &mut buffer, &mut stack, &mut stdout_lock)
84+
.unwrap();
85+
}
86+
}

examples/example.rs

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ extern crate zap;
22

33
use zap::{compile, Environment, FilterInput, Runner};
44

5+
use std::borrow::Cow;
56
use std::io::stdout;
67

78
#[derive(Clone)]
@@ -86,9 +87,9 @@ impl Runner<PersonNums, PersonStrs, PersonFilters> for Person {
8687
}
8788
}
8889

89-
fn str_var(&self, var: PersonStrs) -> &str {
90+
fn str_var(&self, var: PersonStrs) -> Cow<str> {
9091
match var {
91-
PersonStrs::Name => &self.name,
92+
PersonStrs::Name => self.name.as_str().into(),
9293
}
9394
}
9495

@@ -116,19 +117,26 @@ impl Runner<PersonNums, PersonStrs, PersonFilters> for Person {
116117
unreachable!()
117118
}
118119

119-
fn filter_str(&self, filter: PersonFilters, _args: &[f64], input: &str, buffer: &mut String) {
120+
fn filter_str(
121+
&self,
122+
filter: PersonFilters,
123+
_args: &[f64],
124+
input: Cow<str>,
125+
buffer: &mut String,
126+
) {
120127
match filter {
121-
PersonFilters::ToUpper => for c in input.as_bytes() {
122-
buffer.push(c.to_ascii_uppercase() as char)
123-
},
128+
PersonFilters::ToUpper => {
129+
for c in input.as_bytes() {
130+
buffer.push(c.to_ascii_uppercase() as char)
131+
}
132+
}
124133
_ => unreachable!(),
125134
}
126135
}
127136
}
128137

129138
fn main() {
130-
let template =
131-
"{{provider}} {{provider_code + 4}} {{id}} {{name | toupper}} {{age | sqrt}} {{weight / 2.2 | round 2}}kg\n";
139+
let template = "{{provider}} {{provider_code + 4}} {{id}} {{name | toupper}} {{age | sqrt}} {{weight / 2.2 | round 2}}kg\n";
132140

133141
let env = Provider {
134142
provider: "apns".to_string(),

src/bytecode.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
use super::{Environment, FilterInput, Runner};
44
use ast::*;
5+
use std::borrow::Cow;
56
use std::fmt::Debug;
67
use std::io::Write;
78
use tokenizer::Operator;
@@ -120,7 +121,7 @@ impl<
120121
//CallRegStr could probably do without this string allocation
121122
let string = pop!(stack).to_string();
122123
buffer.clear();
123-
runner.filter_str(id, args, &string, buffer);
124+
runner.filter_str(id, args, Cow::from(string), buffer);
124125
write!(output, "{}", buffer)?
125126
}
126127
}

src/lib.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ pub mod bytecode;
33
pub mod optimizer;
44
pub mod tokenizer;
55

6+
use std::borrow::Cow;
67
use std::fmt::Debug;
78

89
pub use bytecode::Bytecode;
@@ -13,8 +14,7 @@ pub enum FilterInput<StrEnum> {
1314
Stringified,
1415
}
1516

16-
pub trait Environment<'a, NumEnum: 'a, StrEnum: 'a + Debug + PartialEq, FilterEnum: 'a>
17-
{
17+
pub trait Environment<'a, NumEnum: 'a, StrEnum: 'a + Debug + PartialEq, FilterEnum: 'a> {
1818
fn num_constant(&self, &str) -> Option<f64>;
1919
fn str_constant(&'a self, &str) -> Option<&'a str>;
2020

@@ -28,13 +28,13 @@ pub trait Environment<'a, NumEnum: 'a, StrEnum: 'a + Debug + PartialEq, FilterEn
2828
#[allow(unused)]
2929
pub trait Runner<NumEnum, StrEnum, FilterEnum> {
3030
fn num_var(&self, NumEnum) -> f64;
31-
fn str_var(&self, StrEnum) -> &str;
31+
fn str_var(&self, StrEnum) -> Cow<str>;
3232

3333
fn filter_num(&self, FilterEnum, &[f64], f64) -> f64;
3434

3535
// the fourth argument is a reusable buffer to reduce allocation
3636
fn filter_id(&self, FilterEnum, &[f64], StrEnum, &mut String);
37-
fn filter_str(&self, FilterEnum, &[f64], &str, &mut String);
37+
fn filter_str(&self, FilterEnum, &[f64], Cow<str>, &mut String);
3838
}
3939

4040
pub fn compile<

zap-derive/.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
2+
/target
3+
**/*.rs.bk
4+
Cargo.lock

zap-derive/Cargo.toml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[package]
2+
authors = ["Josh Leverette <coder543@gmail.com>"]
3+
name = "zap_derive"
4+
version = "0.1.0"
5+
6+
[lib]
7+
proc-macro = true
8+
9+
[dependencies]
10+
quote = "0.5.2"
11+
syn = { version = "0.13.10", features = ["extra-traits"] }

0 commit comments

Comments
 (0)