Skip to content

Commit 161398d

Browse files
Merge pull request #3 from kampffrosch94/switcharoo
Add proxy attribute
2 parents 67c63b3 + 963f1b9 commit 161398d

3 files changed

Lines changed: 175 additions & 10 deletions

File tree

quicksilver/tests/it/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
mod basic;
22
mod cenum;
33
mod containers;
4+
mod proxy;
45
mod regression;
56
mod rust_enum;
67
mod tilemap;

quicksilver/tests/it/proxy.rs

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
use std::collections::HashMap;
2+
3+
use quicksilver::{Quicksilver, json::from_json, reflections_ref::reflect_ref};
4+
5+
#[derive(PartialEq, Debug)]
6+
struct Entity {
7+
id: u32,
8+
generation: u32,
9+
}
10+
11+
#[derive(PartialEq, Debug)]
12+
#[repr(transparent)]
13+
struct EntityWrapper(Entity);
14+
15+
impl ::quicksilver::Quicksilver for EntityWrapper {
16+
const MIRROR: ::quicksilver::Type = ::quicksilver::Type::Struct(&::quicksilver::Struct {
17+
name: "EntityWrapper",
18+
size: ::std::mem::size_of::<Self>(),
19+
align: align_of::<Self>(),
20+
fields: &[
21+
::quicksilver::Field {
22+
name: "id",
23+
ty: u32::MIRROR,
24+
offset: ::std::mem::offset_of!(Self, 0.id),
25+
},
26+
::quicksilver::Field {
27+
name: "generation",
28+
ty: u32::MIRROR,
29+
offset: ::std::mem::offset_of!(Self, 0.generation),
30+
},
31+
],
32+
});
33+
}
34+
35+
#[derive(PartialEq, Debug, Quicksilver)]
36+
struct Container {
37+
#[quicksilver(proxy(Entity, EntityWrapper))]
38+
leader: Entity,
39+
#[quicksilver(proxy(Entity, EntityWrapper))]
40+
followers: Vec<Entity>,
41+
#[quicksilver(proxy(Entity, EntityWrapper))]
42+
mappings: HashMap<u32, Entity>,
43+
}
44+
45+
#[test]
46+
fn subst_roundtrip() {
47+
let mut val = Container {
48+
leader: Entity {
49+
id: 1,
50+
generation: 1,
51+
},
52+
followers: vec![
53+
Entity {
54+
id: 2,
55+
generation: 1,
56+
},
57+
Entity {
58+
id: 3,
59+
generation: 701,
60+
},
61+
Entity {
62+
id: 4,
63+
generation: 1,
64+
},
65+
],
66+
mappings: vec![(
67+
23,
68+
Entity {
69+
id: 23,
70+
generation: 12,
71+
},
72+
)]
73+
.into_iter()
74+
.collect(),
75+
};
76+
let s = reflect_ref(&mut val).to_json();
77+
println!("{}", &s);
78+
let val2 = from_json::<Container>(&s);
79+
dbg!(&val2);
80+
assert_eq!(val, val2);
81+
}
82+
83+
#[derive(PartialEq, Debug, Quicksilver)]
84+
enum ContainerEnum {
85+
One(#[quicksilver(proxy(Entity, EntityWrapper))] Entity),
86+
More {
87+
#[quicksilver(proxy(Entity, EntityWrapper))]
88+
followers: Vec<Entity>,
89+
},
90+
}
91+
92+
#[test]
93+
fn subst_roundtrip_enum_one() {
94+
let mut val = ContainerEnum::One(Entity {
95+
id: 1,
96+
generation: 1,
97+
});
98+
let s = reflect_ref(&mut val).to_json();
99+
println!("{}", &s);
100+
let val2 = from_json::<ContainerEnum>(&s);
101+
dbg!(&val2);
102+
assert_eq!(val, val2);
103+
}
104+
105+
#[test]
106+
fn subst_roundtrip_enum_more() {
107+
let mut val = ContainerEnum::More {
108+
followers: vec![
109+
Entity {
110+
id: 2,
111+
generation: 1,
112+
},
113+
Entity {
114+
id: 3,
115+
generation: 701,
116+
},
117+
Entity {
118+
id: 4,
119+
generation: 1,
120+
},
121+
],
122+
};
123+
let s = reflect_ref(&mut val).to_json();
124+
println!("{}", &s);
125+
let val2 = from_json::<ContainerEnum>(&s);
126+
dbg!(&val2);
127+
assert_eq!(val, val2);
128+
}

quicksilver_derive/src/lib.rs

Lines changed: 46 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -220,20 +220,47 @@ fn parse_fields(input: TokenStream) -> Result<Vec<Field>, MacroError> {
220220

221221
fn parse_field(mut buffer: &[TokenTree]) -> Result<Field, MacroError> {
222222
let mut skip = false;
223+
let mut substitution = None;
223224
if matches!(&buffer[0], TT::Punct(c) if c.as_char() == '#') {
224225
if let TT::Group(attribute_group) = &buffer[1] {
225226
for a in chunked(attribute_group.stream(), 2) {
226-
let [name, group] = &a[..] else {
227+
let [name, group_tt] = &a[..] else {
227228
unreachable!()
228229
};
229230
if matches!(name, TT::Ident(s) if s.to_string() == "quicksilver") {
230-
let TT::Group(group) = group else {
231-
panic!("Expected group.")
231+
let TT::Group(group) = group_tt else {
232+
error_single!(group_tt, "Expected TokenTree::Group.")
232233
};
233-
for attr in group.stream() {
234-
if matches!(attr, TT::Ident(s) if s.to_string() == "skip") {
234+
// dbg!(&group);
235+
let mut it = group.stream().into_iter();
236+
match (it.next(), it.next()) {
237+
(Some(TT::Ident(s)), None) if s.to_string() == "skip" => {
235238
skip = true;
236239
}
240+
(Some(TT::Ident(p)), Some(ref proxy_tt @ TT::Group(ref subst_group)))
241+
if p.to_string() == "proxy" =>
242+
{
243+
let mut it = subst_group.stream().into_iter();
244+
match (it.next(), it.next(), it.next(), it.next()) {
245+
(
246+
Some(TT::Ident(from)),
247+
Some(TT::Punct(c)),
248+
Some(TT::Ident(to)),
249+
None,
250+
) if c.as_char() == ',' => {
251+
substitution = Some((from.to_string(), to.to_string()));
252+
}
253+
_ => {
254+
error_single!(
255+
&proxy_tt,
256+
"Wrong arguments for proxy atttribute."
257+
)
258+
}
259+
}
260+
}
261+
_ => {
262+
error_single!(group_tt, "Unknown attribute");
263+
}
237264
}
238265
}
239266
}
@@ -243,15 +270,15 @@ fn parse_field(mut buffer: &[TokenTree]) -> Result<Field, MacroError> {
243270

244271
let mut iter = buffer.iter();
245272

246-
match (iter.next(), iter.next(), iter.next()) {
273+
let mut r = match (iter.next(), iter.next(), iter.next()) {
247274
(Some(TT::Ident(ty)), None, None) => {
248275
let name = None;
249276
let mirror = parse_mirror(&buffer, &ty.to_string(), skip)?;
250-
Ok(Field {
277+
Field {
251278
name,
252279
mirror,
253280
ty: ty.to_string(),
254-
})
281+
}
255282
}
256283
(Some(TT::Ident(name)), Some(TT::Punct(colon)), Some(TT::Ident(ty)))
257284
if colon.as_char() == ':' =>
@@ -264,7 +291,7 @@ fn parse_field(mut buffer: &[TokenTree]) -> Result<Field, MacroError> {
264291
.map(|it| it.to_string())
265292
.collect::<Vec<_>>()
266293
.join("");
267-
Ok(Field { name, mirror, ty })
294+
Field { name, mirror, ty }
268295
}
269296
(Some(TT::Ident(ty)), Some(TT::Punct(stair)), Some(_)) if stair.as_char() == '<' => {
270297
let name = None;
@@ -274,15 +301,24 @@ fn parse_field(mut buffer: &[TokenTree]) -> Result<Field, MacroError> {
274301
.map(|it| it.to_string())
275302
.collect::<Vec<_>>()
276303
.join("");
277-
Ok(Field { name, mirror, ty })
304+
Field { name, mirror, ty }
278305
}
279306
_ => {
280307
error!(
281308
&[buffer[0].clone(), buffer.last().unwrap().clone()],
282309
"Quicksilver can't parse this."
283310
)
284311
}
312+
};
313+
314+
if let Some((from, to)) = substitution {
315+
if let Some(ref mut name) = r.name {
316+
*name = name.replace(&from, &to);
317+
}
318+
r.mirror = r.mirror.replace(&from, &to);
285319
}
320+
321+
Ok(r)
286322
}
287323

288324
fn parse_mirror(buffer: &[TokenTree], ty: &str, skip: bool) -> Result<String, MacroError> {

0 commit comments

Comments
 (0)