Skip to content
This repository was archived by the owner on Oct 23, 2025. It is now read-only.

Commit 6286d97

Browse files
committed
Derive tuple structs and add a test
1 parent 4d3d4f8 commit 6286d97

File tree

3 files changed

+107
-24
lines changed

3 files changed

+107
-24
lines changed

output_derive/Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,8 @@ proc-macro = true
1010
syn = "0.15"
1111
quote = "0.6"
1212
proc-macro2 = "0.4"
13+
14+
[dev-dependencies]
15+
output = { version = "0.1", path = ".." }
16+
serde = "1.0.79"
17+
serde_derive = "1.0.79"

output_derive/src/lib.rs

Lines changed: 41 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -16,38 +16,55 @@ pub fn render_output(input: TokenStream) -> TokenStream {
1616
let ast: DeriveInput = parse_macro_input!(input as DeriveInput);
1717

1818
let name = &ast.ident;
19-
let fields: Vec<_> = match ast.data {
19+
let render_span = match ast.data {
2020
Data::Struct(s) => match s.fields {
21-
Fields::Named(..) => s
22-
.fields
23-
.iter()
24-
.map(|x| {
25-
let x = x.ident.clone().unwrap();
26-
(x.to_string(), quote!(#x))
27-
}).collect(),
28-
Fields::Unnamed(..) => s
29-
.fields
30-
.iter()
31-
.enumerate()
32-
.map(|(i, _)| (i.to_string(), quote!(#i)))
33-
.collect(),
21+
Fields::Named(..) => {
22+
let fields = s.fields.iter().map(|f| {
23+
let x = f.ident.clone().unwrap();
24+
quote!(#x)
25+
});
26+
let names = s
27+
.fields
28+
.iter()
29+
.map(|f| f.ident.clone().unwrap().to_string());
30+
quote! {
31+
let mut span = output::components::span();
32+
#(
33+
span = span.add_item(#names);
34+
span = span.add_item(": ");
35+
span = span.add_item(output::components::text(&self.#fields.to_string()));
36+
span = span.add_item("\n");
37+
)*
38+
span.render_for_humans(fmt)?;
39+
}
40+
}
41+
Fields::Unnamed(..) => {
42+
let field_count = s.fields.iter().count();
43+
let fields = (0..field_count)
44+
.fold(Vec::new(), |mut res, i| {
45+
res.push(quote! { span = span.add_item(output::components::text(&self.#i.to_string())); });
46+
if i < field_count - 1 {
47+
res.push(quote! { span = span.add_item(", "); });
48+
}
49+
res
50+
});
51+
52+
quote! {
53+
let mut span = output::components::span();
54+
span = span.add_item("(");
55+
#(#fields)*
56+
span = span.add_item(")");
57+
span.render_for_humans(fmt)?;
58+
}
59+
}
3460
_ => panic!("Unit structs not supported for now, sorry."),
3561
},
3662
_ => panic!("Only structs supported for now, sorry."),
3763
};
38-
let names = fields.iter().map(|(name, _)| name);
39-
let fields = fields.iter().map(|(_, ident)| ident);
4064
let exp = quote! {
4165
impl output::Render for #name {
4266
fn render_for_humans(&self, fmt: &mut output::human::Formatter) -> Result<(), output::Error> {
43-
let mut span = output::components::span();
44-
#(
45-
span = span.add_item(#names);
46-
span = span.add_item(": ");
47-
span = span.add_item(output::components::text(&self.#fields.to_string()));
48-
span = span.add_item("\n");
49-
)*
50-
span.render_for_humans(fmt)?;
67+
#render_span
5168
Ok(())
5269
}
5370

output_derive/tests/structs.rs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
extern crate output;
2+
#[macro_use]
3+
extern crate output_derive;
4+
#[macro_use]
5+
extern crate serde_derive;
6+
7+
#[test]
8+
fn struct_with_named_fields_of_primitive_types() -> Result<(), output::Error> {
9+
#[derive(Serialize, RenderOutput)]
10+
struct ErrorMessage {
11+
code: i32,
12+
name: String,
13+
message: String,
14+
}
15+
16+
let human = output::human::test();
17+
let json = output::json::test();
18+
let mut out = output::new()
19+
.add_target(human.target())
20+
.add_target(json.target());
21+
22+
out.print(&ErrorMessage {
23+
code: 42,
24+
name: String::from("info"),
25+
message: String::from("Derive works"),
26+
})?;
27+
28+
assert_eq!(
29+
human.to_string(),
30+
"code: 42\n\
31+
name: info\n\
32+
message: Derive works\n\n"
33+
);
34+
35+
assert_eq!(
36+
json.to_string(),
37+
"{\"code\":42,\"name\":\"info\",\"message\":\"Derive works\"}\n\n"
38+
);
39+
40+
Ok(())
41+
}
42+
43+
#[test]
44+
fn tuple_struct_of_primitive_types() -> Result<(), output::Error> {
45+
#[derive(Serialize, RenderOutput)]
46+
struct ErrorMessage(i32, String);
47+
48+
let human = output::human::test();
49+
let json = output::json::test();
50+
let mut out = output::new()
51+
.add_target(human.target())
52+
.add_target(json.target());
53+
54+
out.print(&ErrorMessage(42, String::from("Derive works")))?;
55+
56+
assert_eq!(human.to_string(), "(42, Derive works)\n");
57+
58+
assert_eq!(json.to_string(), "[42,\"Derive works\"]\n\n");
59+
60+
Ok(())
61+
}

0 commit comments

Comments
 (0)