nop_json_derive/
lib.rs

1//! This is helper crate intended to be used internally in nop_json crate.
2//! Don't use it directly. See nop_json crate for details.
3
4use proc_macro::TokenStream;
5use proc_macro2::Span;
6use quote::quote;
7use syn::{self, DeriveInput, Data, Attribute, Ident, Meta, NestedMeta, Lit, LitByteStr, Generics, ImplGenerics, TypeGenerics, GenericParam, TypeParam};
8use std::borrow::Cow;
9use std::mem;
10use std::collections::{HashMap, HashSet};
11
12const HEX_DIGITS: [u8; 16] = [b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'A', b'B', b'C', b'D', b'E', b'F'];
13
14/// This is copy/paste fn from nop_json
15fn escape(s: &str) -> Cow<str>
16{	let bytes = s.as_bytes();
17	if let Some(mut pos) = bytes.iter().position(|c| match *c {b'"' | b'\\' | 0..=31 => true, _ => false})
18	{	let mut buffer = Vec::with_capacity(bytes.len() + 8);
19		let mut from = 0;
20		loop
21		{	buffer.extend_from_slice(&bytes[from .. pos]);
22			let c = bytes[pos];
23			if c >= 32
24			{	buffer.push(b'\\');
25				buffer.push(c);
26			}
27			else
28			{	match c
29				{	9 =>
30					{	buffer.push(b'\\');
31						buffer.push(b't');
32					}
33					13 =>
34					{	buffer.push(b'\\');
35						buffer.push(b'r');
36					}
37					10 =>
38					{	buffer.push(b'\\');
39						buffer.push(b'n');
40					}
41					8 =>
42					{	buffer.push(b'\\');
43						buffer.push(b'b');
44					}
45					12 =>
46					{	buffer.push(b'\\');
47						buffer.push(b'f');
48					}
49					_ =>
50					{	buffer.push(b'\\');
51						buffer.push(b'u');
52						buffer.push(b'0');
53						buffer.push(b'0');
54						buffer.push(HEX_DIGITS[(c >> 4) as usize]);
55						buffer.push(HEX_DIGITS[(c & 0xF) as usize]);
56					}
57				}
58			}
59			from = pos + 1;
60			if let Some(new_pos) = &bytes[from ..].iter().position(|c| match *c {b'"' | b'\\' | 0..=31 => true, _ => false})
61			{	pos = from + *new_pos;
62			}
63			else
64			{	buffer.extend_from_slice(&bytes[from .. ]);
65				break;
66			}
67		}
68		Cow::Owned(String::from_utf8(buffer).unwrap())
69	}
70	else
71	{	Cow::Borrowed(s)
72	}
73}
74
75/// To generate TryFromJson implementation for any struct or enum, where all members also implement TryFromJson
76/// use `#[derive(TryFromJson)]`.
77///
78/// See nop_json crate for details.
79#[proc_macro_derive(TryFromJson, attributes(json, json_ignore))]
80pub fn derive_try_from_json(input: TokenStream) -> TokenStream
81{	let ast: &mut DeriveInput = &mut syn::parse(input).unwrap();
82	match impl_try_from_json(ast)
83	{	Ok(ts) => ts,
84		Err(error) =>
85		{	panic!("{}", error);
86		}
87	}
88}
89
90fn impl_try_from_json(ast: &mut DeriveInput) -> Result<TokenStream, String>
91{	let name = &ast.ident;
92	let mut json_ignore = HashMap::new();
93	let mut is_ignore_all = get_json_ignore(&ast.attrs, usize::MAX, &mut json_ignore, false)?;
94	let mut variants = Vec::new();
95	let mut enum_variant_cannot_be = HashMap::new();
96	let mut code = quote!();
97	let mut code_2 = quote!();
98	let mut code_3 = quote!();
99	match &ast.data
100	{	Data::Struct(data_struct) =>
101		{	for field in data_struct.fields.iter()
102			{	if let Some(ref field_name) = field.ident
103				{	let mut json_str = get_json_name(&field.attrs, "struct field")?.unwrap_or_else(|| field_name.to_string());
104					let is_transient = json_str.is_empty();
105					if is_transient
106					{	json_str = field_name.to_string();
107					}
108					// code
109					if !is_transient
110					{	code = quote!( #code let mut #field_name = None; );
111					}
112					// code_2
113					let b = LitByteStr::new(json_str.as_bytes(), Span::call_site());
114					if !is_transient
115					{	code_2 = quote!( #code_2 #b => #field_name = reader.read_prop(#json_str)?, );
116					}
117					else
118					{	code_2 = quote!( #code_2 #b => {let skip: () = reader.read_prop(#json_str)?;}, );
119					}
120					// code_3
121					if !is_transient
122					{	code_3 = quote!( #code_3 #field_name: #field_name.unwrap_or_default(), );
123					}
124					else
125					{	code_3 = quote!( #code_3 #field_name: Default::default(), );
126					}
127				}
128			}
129			code_3 = quote!( let result = Self{#code_3} );
130		},
131		Data::Enum(data_enum) =>
132		{	let enum_json_name = get_json_name(&ast.attrs, "enum")?.unwrap_or_default();
133			let mut fields = Vec::new();
134			let mut fields_by_json_name = HashMap::new();
135			// scan variants
136			for (n_variant, variant) in data_enum.variants.iter().enumerate()
137			{	let variant_name = &variant.ident;
138				let (variant_name_str, json_names) = get_json_name_for_enum_variant(&variant.attrs, variant_name, variant.fields.len())?;
139				is_ignore_all = get_json_ignore(&variant.attrs, n_variant, &mut json_ignore, is_ignore_all)?;
140				let variant_name_str = variant_name_str.unwrap_or_else(|| variant_name.to_string());
141				let mut n_field = 0;
142				for json_name in &json_names
143				{	if !json_name.is_empty() // if not transient
144					{	let cur = fields_by_json_name.get_mut(json_name);
145						match cur
146						{	None =>
147							{	fields_by_json_name.insert(json_name.clone(), (Ident::new(&format!("val_{}_{}", variant_name, n_field), Span::call_site()), 1));
148							}
149							Some(cur) =>
150							{	cur.1 += 1;
151							}
152						}
153						let (val_field, n_occurances) = fields_by_json_name.get(json_name).unwrap();
154						fields.push((variants.len(), json_name.clone(), val_field.clone(), *n_occurances>1));
155						n_field += 1;
156					}
157					else
158					{	fields.push((variants.len(), json_name.clone(), Ident::new("u", Span::call_site()), false));
159					}
160				}
161				variants.push((variant_name, variant_name_str, json_names));
162			}
163			// scan json_ignore
164			for (json_name, ignore_in_variants) in &json_ignore
165			{	if ignore_in_variants.len() != variants.len() && !ignore_in_variants.contains(&usize::MAX)
166				{	// if json_name is ignored not in all variants
167					for (n_variant, (variant_name, _variant_name_str, json_names)) in variants.iter().enumerate()
168					{	if !ignore_in_variants.contains(&n_variant) && !json_names.contains(json_name)
169						{	// if json_name is not ignored in variant n_variant
170							let enum_name = format!("{}::{}", name, variant_name);
171							let var_name = Ident::new(&format!("enum_variant_cannot_be_{}", n_variant), Span::call_site());
172							let code_c = quote!
173							(	if let Some(prop_name) = #var_name
174								{	return Err(reader.format_error_fmt(format_args!("Field {} is invalid in variant {}", String::from_utf8_lossy(prop_name), #enum_name)));
175								}
176							);
177							code = quote!( #code let mut #var_name: Option<&[u8]> = None; );
178							enum_variant_cannot_be.insert(n_variant, (var_name, code_c));
179						}
180					}
181				}
182			}
183			// form resulting code parts
184			let mut code_4 = quote!();
185			for (n_variant, (variant_name, variant_name_str, json_names)) in variants.iter().enumerate()
186			{	let mut code_5 = quote!();
187				let has_fields = !json_names.is_empty();
188				for json_name in json_names
189				{	if !json_name.is_empty() // if not transient
190					{	let (val_field, n_occurances) = fields_by_json_name.get(json_name).unwrap();
191						if *n_occurances <= 1
192						{	code_5 = quote!( #code_5 #val_field.unwrap_or_default(), );
193						}
194						else
195						{	code_5 = quote!( #code_5 #val_field.try_into().unwrap_or_default(), );
196						}
197					}
198					else
199					{	code_5 = quote!( #code_5 Default::default(), );
200					}
201				}
202				let pref_variant_name = Ident::new(&format!("Var{}", variant_name), Span::call_site());
203				if !enum_json_name.is_empty()
204				{	let b = LitByteStr::new(variant_name_str.as_bytes(), Span::call_site());
205					code_2 = quote!( #code_2 #b => EnumVariant::#pref_variant_name, );
206					code_3 = quote!( #code_3 #pref_variant_name, );
207					if has_fields
208					{	code_5 = quote!( (#code_5) );
209					}
210					let mut code_c = quote!();
211					if let Some((_, code_c_2)) = enum_variant_cannot_be.get(&n_variant)
212					{	code_c = quote!(#code_c #code_c_2);
213					};
214					code_4 = quote!( #code_4 EnumVariant::#pref_variant_name => {#code_c Self::#variant_name #code_5}, );
215				}
216			}
217			if !enum_json_name.is_empty()
218			{	code = quote!( #code enum EnumVariant {Invalid, #code_3} let mut enum_variant_field = EnumVariant::Invalid; );
219				let b = LitByteStr::new(enum_json_name.as_bytes(), Span::call_site());
220				code_2 = quote!
221				{	#b =>
222					{	enum_variant_field = match reader.read_bytes()?
223						{	#code_2
224							_ => return Err(reader.format_error("Invalid enum variant"))
225						};
226					},
227				};
228			}
229			//
230			let mut code_5 = quote!();
231			for (_n_variant, json_name, val_field, is_dup_json_name) in &fields
232			{	if !json_name.is_empty() // if not transient
233				{	// code
234					let (_val_field, n_occurances) = fields_by_json_name.get(json_name).unwrap();
235					if *n_occurances <= 1
236					{	// is not one of duplicate json names
237						code = quote!( #code let mut #val_field = None; );
238					}
239					else if !*is_dup_json_name
240					{	// is first occurance of duplicate json name
241						code = quote!( #code let mut #val_field = nop_json::Value::Null; );
242					}
243					// code_2
244					if !*is_dup_json_name
245					{	let b = LitByteStr::new(json_name.as_bytes(), Span::call_site());
246						code_2 = quote!( #code_2 #b => #val_field = reader.read_prop(#json_name)?, );
247					}
248					// code_5
249					code_5 = quote!( #code_5 #val_field, );
250				}
251			}
252			if !enum_json_name.is_empty()
253			{	code_3 = quote!
254				{	let result = match enum_variant_field
255					{	EnumVariant::Invalid => return Err(reader.format_error(concat!("Field ", #enum_json_name, " is required"))),
256						#code_4
257					}
258				};
259			}
260			else
261			{	for n_variant in 0..data_enum.variants.len()
262				{	let mut code_6 = quote!();
263					let mut code_7 = quote!();
264					let mut has_fields = false;
265					for (field_n_variant, json_name, val_field, _is_dup_json_name) in &fields
266					{	if *field_n_variant == n_variant
267						{	if !json_name.is_empty() // if not transient
268							{	code_6 = quote!( #code_6 Some(#val_field), );
269								code_7 = quote!( #code_7 #val_field, );
270							}
271							else
272							{	code_7 = quote!( #code_7 Default::default(), );
273							}
274							has_fields = true;
275						}
276						else if !json_name.is_empty() // if not transient
277						{	code_6 = quote!( #code_6 None, );
278						}
279					}
280					if has_fields
281					{	code_7 = quote!( (#code_7) );
282					}
283					let variant_name = &data_enum.variants[n_variant].ident;
284					let mut code_c = quote!();
285					if let Some((_, code_c_2)) = enum_variant_cannot_be.get(&n_variant)
286					{	code_c = quote!(#code_c #code_c_2);
287					};
288					code_3 = quote!( #code_3 (#code_6) => {#code_c Self::#variant_name #code_7}, );
289				}
290				code_3 = quote!( let result = match (#code_5) { #code_3 _ => return Err(reader.format_error("Invalid combination of properties"))} );
291			}
292		},
293		Data::Union(_data_union) =>
294		{	return Err("Cannot deserialize union".to_string());
295		},
296	};
297	// ignore?
298	let code_8 = if is_ignore_all
299	{	// ignore all
300		quote!( _ => { reader.read::<()>()? })
301	}
302	else
303	{	let mut code_8 = quote!();
304		// ignore only names from "json_ignore"
305		for (json_name, ignore_in_variants) in json_ignore
306		{	let b = LitByteStr::new(json_name.as_bytes(), Span::call_site());
307			let mut code_9 = quote!();
308			if ignore_in_variants.len() != variants.len() && !ignore_in_variants.contains(&usize::MAX)
309			{	// if json_name is ignored not in all variants
310				for (n_variant, (_variant_name, _variant_name_str, json_names)) in variants.iter().enumerate()
311				{	if !ignore_in_variants.contains(&n_variant) && !json_names.contains(&json_name)
312					{	// if json_name is not ignored in variant n_variant
313						let var_name = &enum_variant_cannot_be.get(&n_variant).unwrap().0;
314						code_9 = quote!( #code_9 #var_name = Some(#b); );
315					}
316				}
317			}
318			code_8 = quote!( #code_8 #b => { reader.read::<()>()?; #code_9 }, );
319		}
320		quote!( #code_8 _ => {return Err(reader.format_error_fmt(format_args!("Invalid property: {}", String::from_utf8_lossy(reader.get_key()))))} )
321	};
322	// get generic parameters of this type (like struct<T> {...})
323	let (impl_generics, ty_generics, where_clause) = get_generics_debug_to_json(&ast.generics);
324	code = quote!
325	{	impl #impl_generics nop_json::TryFromJson for #name #ty_generics #where_clause
326		{	fn try_from_json<T>(reader: &mut nop_json::Reader<T>) -> std::io::Result<Self> where T: Iterator<Item=u8>
327			{	use nop_json::ValidateJson;
328				use std::convert::TryInto;
329				#code
330				reader.read_object_use_buffer
331				(	|reader|
332					{	match reader.get_key()
333						{	#code_2
334							#code_8
335						}
336						Ok(())
337					}
338				)?;
339				#code_3;
340				result.validate_json().map_err(|msg| reader.format_error(&msg))
341			}
342		}
343	};
344	// to see what i produced, uncomment the panic!() below, and try to compile your code with #[derive(TryFromJson)]
345//panic!(code.to_string());
346	// done
347	Ok(code.into())
348}
349
350
351/// To generate DebugToJson implementation for any struct or enum, where all members also implement DebugToJson
352/// use `#[derive(DebugToJson)]`.
353///
354/// See nop_json crate for details.
355#[proc_macro_derive(DebugToJson, attributes(json))]
356pub fn derive_debug_to_json(input: TokenStream) -> TokenStream
357{	let ast: &mut DeriveInput = &mut syn::parse(input).unwrap();
358	match impl_debug_or_write_to_json(ast, false)
359	{	Ok(ts) => ts,
360		Err(error) =>
361		{	panic!("{}", error);
362		}
363	}
364}
365
366fn impl_debug_or_write_to_json(ast: &mut DeriveInput, is_write_to_json: bool) -> Result<TokenStream, String>
367{	let name = &ast.ident; // struct or enum name
368	let mut code = quote!();
369	match &ast.data
370	{	Data::Struct(data_struct) =>
371		{	let mut n_field = 0;
372			for field in data_struct.fields.iter()
373			{	if let Some(ref field_name) = field.ident
374				{	let json_str = get_json_name(&field.attrs, "struct field")?.unwrap_or_else(|| field_name.to_string());
375					if !json_str.is_empty() // if not transient
376					{	let fmt = if n_field == 0
377						{	format!("{{{{\"{}\":", escape(&json_str))
378						}
379						else
380						{	format!(",\"{}\":", escape(&json_str))
381						};
382						code = if !is_write_to_json
383						{	quote!( #code write!(out, #fmt)?; nop_json::DebugToJson::fmt(&self.#field_name, out)?; )
384						}
385						else
386						{	quote!( #code write!(out, #fmt)?; nop_json::WriteToJson::write_to_json(&self.#field_name, out)?; )
387						};
388						n_field += 1;
389					}
390				}
391			}
392			if n_field == 0
393			{	code = quote!( #code write!(out, "{{}}") );
394			}
395			else
396			{	code = quote!( #code write!(out, "}}") );
397			}
398		},
399		Data::Enum(data_enum) =>
400		{	let enum_json_name = get_json_name(&ast.attrs, "enum")?.unwrap_or_default();
401			for variant in &data_enum.variants
402			{	let variant_name = &variant.ident;
403				let (variant_name_str, json_names) = get_json_name_for_enum_variant(&variant.attrs, variant_name, variant.fields.len())?;
404				let mut n_field = 0;
405				let mut has_named_fields = false;
406				let mut code_2 = quote!();
407				let mut code_3 = quote!();
408				if !enum_json_name.is_empty()
409				{	let variant_name_str = variant_name_str.unwrap_or_else(|| variant_name.to_string());
410					let fmt = format!("{{{{\"{}\":\"{}\"", escape(&enum_json_name), escape(&variant_name_str));
411					code_3 = quote!( #code_3 write!(out, #fmt)?; );
412					has_named_fields = true;
413				}
414				for json_name in json_names
415				{	let is_transient = json_name.is_empty();
416					// code_2
417					let val_field = Ident::new(&format!("{}val_{}", if is_transient {"_"} else {""}, n_field), Span::call_site());
418					code_2 = quote!( #code_2 ref #val_field, );
419					if !is_transient
420					{	// code_3
421						let fmt = if n_field==0 && enum_json_name.is_empty()
422						{	format!("{{{{\"{}\":", escape(&json_name))
423						}
424						else
425						{	format!(",\"{}\":", escape(&json_name))
426						};
427						code_3 = if !is_write_to_json
428						{	quote!( #code_3 write!(out, #fmt)?; nop_json::DebugToJson::fmt(#val_field, out)?; )
429						}
430						else
431						{	quote!( #code_3 write!(out, #fmt)?; nop_json::WriteToJson::write_to_json(#val_field, out)?; )
432						};
433						has_named_fields = true;
434					}
435					//
436					n_field += 1;
437				}
438				if n_field > 0
439				{	code_2 = quote!( (#code_2) );
440				}
441				if !has_named_fields
442				{	code_3 = quote!( #code_3 write!(out, "{{")?; );
443				}
444				code = quote!( #code #name::#variant_name #code_2 => {#code_3} );
445			}
446			code = quote!( match *self {#code} write!(out, "}}") );
447		},
448		Data::Union(_data_union) =>
449		{	return Err("Cannot serialize union".to_string());
450		},
451	};
452	// produce the impl
453	if !is_write_to_json
454	{	// get generic parameters of this type (like struct<T> {...})
455		let (impl_generics, ty_generics, where_clause) = get_generics_debug_to_json(&ast.generics);
456		// impl DebugToJson and impl Debug
457		code = quote!
458		{	impl #impl_generics nop_json::DebugToJson for #name #ty_generics #where_clause
459			{	fn fmt(&self, out: &mut std::fmt::Formatter) -> std::fmt::Result
460				{	#code
461				}
462			}
463			impl #impl_generics std::fmt::Debug for #name #ty_generics #where_clause
464			{	fn fmt(&self, out: &mut std::fmt::Formatter) -> std::fmt::Result
465				{	nop_json::DebugToJson::fmt(self, out)
466				}
467			}
468		};
469	}
470	else
471	{	// get generic parameters of this type (like struct<T> {...})
472		let mut generics = mem::take(&mut ast.generics);
473		let (impl_generics, ty_generics, where_clause) = get_generics_write_to_json(&mut generics);
474		// impl WriteToJson
475		code = quote!
476		{	impl #impl_generics nop_json::WriteToJson<WriteToJsonPriv1> for #name #ty_generics #where_clause
477			{	fn write_to_json(&self, out: &mut WriteToJsonPriv1) -> std::io::Result<()>
478				{	#code
479				}
480			}
481		};
482	}
483	// to see what i produced, uncomment the panic!() below, and try to compile your code with #[derive(DebugToJson)]
484//panic!(code.to_string());
485	// done
486	Ok(code.into())
487}
488
489fn get_json_name(attrs: &Vec<Attribute>, what: &str) -> Result<Option<String>, String>
490{	let mut result = parse_json_attr(attrs, 0, None)?;
491	if result.0.is_some()
492	{	return Err(format!("Cannot parse #[json(...)] for {}", what));
493	}
494	if result.1.len() > 1
495	{	return Err(format!("#[json(...)] for {} must contain 1 field name", what));
496	}
497	Ok(result.1.pop())
498}
499
500fn get_json_name_for_enum_variant(attrs: &Vec<Attribute>, variant_name: &Ident, n_fields: usize) -> Result<(Option<String>, Vec<String>), String>
501{	parse_json_attr(attrs, n_fields, Some(variant_name))
502}
503
504fn parse_json_attr(attrs: &Vec<Attribute>, n_fields: usize, variant_name: Option<&Ident>) -> Result<(Option<String>, Vec<String>), String>
505{	parse_json_attr_sub(attrs, n_fields, variant_name.is_some()).map_err
506	(	|e|
507		if let Some(variant_name) = variant_name
508		{	format!("Cannot parse #[json(...)] in enum variant {}{}{}", variant_name, if e.is_empty() {""} else {": "}, e)
509		}
510		else
511		{	format!("Cannot parse #[json(...)]{}{}", if e.is_empty() {""} else {": "}, e)
512		}
513	)
514}
515
516fn parse_json_attr_sub(attrs: &Vec<Attribute>, n_fields: usize, is_enum: bool) -> Result<(Option<String>, Vec<String>), String>
517{	let mut group_name = None;
518	let mut json_names = Vec::new();
519	let mut is_var_str = false;
520	for a in attrs
521	{	match a.parse_meta()
522		{	Ok(Meta::List(list)) =>
523			{	if list.path.is_ident("json")
524				{	for a in list.nested
525					{	match a
526						{	NestedMeta::Lit(Lit::Str(s)) =>
527							{	if group_name.is_some() && !is_var_str
528								{	return Err("Couldn't interpret #[json] attribute".to_string());
529								}
530								json_names.push(s.value());
531							},
532							NestedMeta::Meta(Meta::Path(meta)) =>
533							{	if group_name.is_some() && !is_var_str
534								{	return Err("Couldn't interpret #[json] attribute".to_string());
535								}
536								if let Some(name) = meta.get_ident()
537								{	json_names.push(name.to_string());
538								}
539							},
540							NestedMeta::Meta(Meta::List(list)) =>
541							{	if is_enum
542								{	if json_names.len() > 0
543									{	return Err("Couldn't interpret #[json] attribute".to_string());
544									}
545									if let Some(name) = list.path.get_ident()
546									{	group_name = Some(name.to_string());
547										for a in list.nested
548										{	match a
549											{	NestedMeta::Lit(Lit::Str(s)) =>
550												{	json_names.push(s.value());
551												},
552												NestedMeta::Meta(Meta::Path(meta)) =>
553												{	if let Some(name) = meta.get_ident()
554													{	json_names.push(name.to_string());
555													}
556												},
557												_ =>
558												{	return Err("Couldn't interpret #[json] attribute".to_string());
559												}
560											}
561										}
562									}
563									if json_names.len() == 0
564									{	return Err("Couldn't interpret #[json] attribute".to_string());
565									}
566								}
567								else
568								{	return Err("Couldn't interpret #[json] attribute".to_string());
569								}
570							},
571							NestedMeta::Meta(Meta::NameValue(list)) =>
572							{	if is_enum
573								{	if group_name.is_some()
574									{	return Err("Couldn't interpret #[json] attribute".to_string());
575									}
576									if list.path.is_ident("var")
577									{	match list.lit
578										{	Lit::Str(s) =>
579											{	group_name = Some(s.value());
580												is_var_str = true;
581											},
582											_ => {}
583										}
584									}
585									if group_name.is_none()
586									{	return Err("Couldn't interpret #[json] attribute".to_string());
587									}
588								}
589								else
590								{	return Err("Couldn't interpret #[json] attribute".to_string());
591								}
592							},
593							_ =>
594							{	return Err("Couldn't interpret #[json] attribute".to_string());
595							}
596						}
597					}
598				}
599			},
600			_ => {}
601		}
602	}
603	if is_enum
604	{	if json_names.len() != n_fields
605		{	if json_names.len()==0
606			{	return Err(format!("Enum variant must have #[json(name_1, name_2, ...)] or #[json(variant_name(name_1, name_2, ...))] or #[json(var=\"variant_name\", name_1, name_2, ...)]"));
607			}
608			else if n_fields==0 && json_names.len()==1 && group_name.is_none()
609			{	group_name = Some(json_names.pop().unwrap());
610			}
611			else
612			{	return Err(format!("Must specify names for each member"));
613			}
614		}
615	}
616	Ok((group_name, json_names))
617}
618
619fn get_json_ignore(attrs: &Vec<Attribute>, n_variant: usize, json_ignore: &mut HashMap<String, HashSet<usize>>, is_ignore_all: bool) -> Result<bool, String>
620{	let mut has_ignore = false;
621	for a in attrs
622	{	match a.parse_meta()
623		{	Ok(Meta::Path(path)) =>
624			{	if path.is_ident("json_ignore")
625				{	has_ignore = true;
626				}
627			},
628			Ok(Meta::List(list)) =>
629			{	if list.path.is_ident("json_ignore")
630				{	has_ignore = true;
631					for a in list.nested
632					{	let name = match a
633						{	NestedMeta::Lit(Lit::Str(s)) =>
634							{	if is_ignore_all
635								{	return Err("#[json_ignore] after ignoring all".to_string());
636								}
637								Some(s.value())
638							},
639							NestedMeta::Meta(Meta::Path(meta)) =>
640							{	if let Some(name) = meta.get_ident()
641								{	if is_ignore_all
642									{	return Err("#[json_ignore] after ignoring all".to_string());
643									}
644									Some(name.to_string())
645								}
646								else
647								{	None
648								}
649							},
650							_ =>
651							{	None
652							}
653						};
654						if let Some(name) = name
655						{	match json_ignore.get_mut(&name)
656							{	Some(variants) =>
657								{	variants.insert(n_variant);
658								}
659								None =>
660								{	let mut variants = HashSet::new();
661									variants.insert(n_variant);
662									json_ignore.insert(name, variants);
663								}
664							}
665						}
666					}
667				}
668			},
669			_ => {}
670		}
671	}
672	Ok(is_ignore_all || has_ignore && json_ignore.is_empty())
673}
674
675/// get generic parameters of this type (like struct<T> {...})
676fn get_generics_debug_to_json(generics: &Generics) -> (ImplGenerics, TypeGenerics, proc_macro2::TokenStream)
677{	let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
678	// for each generic type add where: DebugToJson
679	let mut wher = quote!();
680	let mut i = 0;
681	for p in &generics.params
682	{	match p
683		{	GenericParam::Type(ty) =>
684			{	let ty = &ty.ident;
685				if i == 0
686				{	wher = if where_clause.is_none() {quote!(where)} else {quote!(#where_clause,)};
687					wher = quote!( #wher #ty: nop_json::DebugToJson );
688				}
689				else
690				{	wher = quote!( #wher, #ty: nop_json::DebugToJson );
691				}
692				i += 1;
693			},
694			_=> {},
695		}
696	}
697	if i == 0
698	{	wher = quote!(#where_clause);
699	}
700	(impl_generics, ty_generics, wher)
701}
702
703/// get generic parameters of this type (like struct<T> {...})
704fn get_generics_write_to_json(generics: &mut Generics) -> (ImplGenerics, proc_macro2::TokenStream, proc_macro2::TokenStream)
705{	let (_impl_generics, ty_generics, where_clause) = generics.split_for_impl();
706	// for each generic type add where: WriteToJson
707	let mut wher = if where_clause.is_none() {quote!(where WriteToJsonPriv1: std::io::Write)} else {quote!(#where_clause, WriteToJsonPriv1: std::io::Write)};
708	for p in &generics.params
709	{	match p
710		{	GenericParam::Type(ty) =>
711			{	let ty = &ty.ident;
712				wher = quote!( #wher, #ty: nop_json::WriteToJson<WriteToJsonPriv1> );
713			},
714			_=> {},
715		}
716	}
717	// add WriteToJsonPriv1 to impl_generics, but not to ty_generics
718	let ty_generics = quote!(#ty_generics);
719	let ident = Ident::new("WriteToJsonPriv1", Span::call_site());
720	generics.params.push(GenericParam::Type(TypeParam {attrs: Default::default(), ident, colon_token: None, bounds: Default::default(), eq_token: None, default: None}));
721	let impl_generics = generics.split_for_impl().0;
722	(impl_generics, ty_generics, wher)
723}
724
725
726/// To generate WriteToJson implementation for any struct or enum, where all members also implement WriteToJson
727/// use `#[derive(WriteToJson)]`.
728///
729/// See nop_json crate for details.
730#[proc_macro_derive(WriteToJson, attributes(json))]
731pub fn derive_write_to_json(input: TokenStream) -> TokenStream
732{	let ast: &mut DeriveInput = &mut syn::parse(input).unwrap();
733	match impl_debug_or_write_to_json(ast, true)
734	{	Ok(ts) => ts,
735		Err(error) =>
736		{	panic!("{}", error);
737		}
738	}
739}
740
741/// To generate ValidateJson implementation that always passes the validation use `#[derive(ValidateJson)]`.
742///
743/// See nop_json crate for details.
744#[proc_macro_derive(ValidateJson)]
745pub fn derive_validate_json(input: TokenStream) -> TokenStream
746{	let ast: &mut DeriveInput = &mut syn::parse(input).unwrap();
747	match impl_validate_json(ast)
748	{	Ok(ts) => ts,
749		Err(error) =>
750		{	panic!("{}", error);
751		}
752	}
753}
754
755fn impl_validate_json(ast: &mut DeriveInput) -> Result<TokenStream, String>
756{	let name = &ast.ident; // struct or enum name
757	// get generic parameters of this type (like struct<T> {...})
758	let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
759	// impl WriteToJson
760	let code = quote!
761	{	impl #impl_generics nop_json::ValidateJson for #name #ty_generics #where_clause {}
762	};
763	// to see what i produced, uncomment the panic!() below, and try to compile your code with #[derive(ValidateJson)]
764//panic!(code.to_string());
765	// done
766	Ok(code.into())
767}