1use proc_macro2::{Span, TokenStream};
46use quote::{format_ident, quote};
47use syn::punctuated::Punctuated;
48use syn::spanned::Spanned;
49use syn::{Data, DeriveInput, Fields};
50
51use crate::naming::{ident_name, to_snake_case};
52
53const RESERVED_FIELDS: [&str; 3] = ["message", "call", "kind"];
56
57enum ClassSpec {
61 One(syn::LitStr),
63 List(Vec<syn::LitStr>, Span),
66}
67
68struct DataEntry {
70 name: String,
71 value: syn::Expr,
72 span: Span,
73}
74
75#[derive(#[automatically_derived]
impl ::core::default::Default for ContainerAttrs {
#[inline]
fn default() -> Self {
ContainerAttrs {
class: ::core::default::Default::default(),
message: ::core::default::Default::default(),
argument_message: ::core::default::Default::default(),
call_none: ::core::default::Default::default(),
kind: ::core::default::Default::default(),
data: ::core::default::Default::default(),
}
}
}Default)]
77struct ContainerAttrs {
78 class: Option<ClassSpec>,
79 message: Option<syn::LitStr>,
80 argument_message: Option<syn::LitStr>,
82 call_none: bool,
84 kind: Option<syn::Ident>,
87 data: Vec<DataEntry>,
89}
90
91fn parse_container_attrs(attrs: &[syn::Attribute], on: &str) -> syn::Result<ContainerAttrs> {
92 let mut out = ContainerAttrs::default();
93 for attr in attrs {
94 if !attr.path().is_ident("condition") {
95 continue;
96 }
97 attr.parse_nested_meta(|meta| {
98 if meta.path.is_ident("class") {
99 if out.class.is_some() {
100 return Err(meta.error("`class` is given twice"));
101 }
102 out.class = Some(if meta.input.peek(syn::token::Paren) {
103 let span = meta.path.span();
104 let content;
105 match ::syn::__private::parse_parens(&meta.input) {
::syn::__private::Ok(parens) => {
content = parens.content;
_ = content;
parens.token
}
::syn::__private::Err(error) => { return ::syn::__private::Err(error); }
};syn::parenthesized!(content in meta.input);
106 let list =
107 Punctuated::<syn::LitStr, ::syn::token::Commasyn::Token![,]>::parse_terminated(&content)?;
108 if list.is_empty() {
109 return Err(meta.error("`class(...)` needs at least one class"));
110 }
111 ClassSpec::List(list.into_iter().collect(), span)
112 } else {
113 ClassSpec::One(meta.value()?.parse()?)
114 });
115 } else if meta.path.is_ident("data") {
116 meta.parse_nested_meta(|entry| {
117 let ident = entry
118 .path
119 .get_ident()
120 .ok_or_else(|| entry.error("a `data` entry is `name = value`"))?
121 .clone();
122 let value: syn::Expr = entry.value()?.parse()?;
123 out.data.push(DataEntry {
124 name: ident_name(&ident),
125 value,
126 span: ident.span(),
127 });
128 Ok(())
129 })?;
130 } else if meta.path.is_ident("message") {
131 if out.message.is_some() {
132 return Err(meta.error("`message` is given twice"));
133 }
134 out.message = Some(meta.value()?.parse()?);
135 } else if meta.path.is_ident("argument_message") {
136 if out.argument_message.is_some() {
137 return Err(meta.error("`argument_message` is given twice"));
138 }
139 out.argument_message = Some(meta.value()?.parse()?);
140 } else if meta.path.is_ident("kind") {
141 if out.kind.is_some() {
142 return Err(meta.error("`kind` is given twice"));
143 }
144 let kind: syn::Ident = meta.value()?.parse()?;
145 if !#[allow(non_exhaustive_omitted_patterns)] match kind.to_string().as_str() {
"error" | "warning" | "message" | "condition" => true,
_ => false,
}matches!(
146 kind.to_string().as_str(),
147 "error" | "warning" | "message" | "condition"
148 ) {
149 return Err(syn::Error::new(
150 kind.span(),
151 "condition kind must be error, warning, message or condition",
152 ));
153 }
154 out.kind = Some(kind);
155 } else if meta.path.is_ident("call") {
156 if out.call_none {
157 return Err(meta.error("`call` is given twice"));
158 }
159 let value: syn::Ident = meta.value()?.parse().map_err(|err| {
160 syn::Error::new(
161 err.span(),
162 "`call` takes `none`: `#[condition(call = none)]` raises the condition \
163 without a call, like R's `call. = FALSE`",
164 )
165 })?;
166 if value != "none" {
167 return Err(syn::Error::new(
168 value.span(),
169 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("unknown `call` value `{0}`; the only one is `none` (`#[condition(call = none)]`: no call, like R\'s `call. = FALSE`)",
value))
})format!(
170 "unknown `call` value `{value}`; the only one is `none` \
171 (`#[condition(call = none)]`: no call, like R's `call. = FALSE`)"
172 ),
173 ));
174 }
175 out.call_none = true;
176 } else {
177 return Err(meta.error(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("unknown `condition` option on {0}; expected `class = \"…\"`, `class(\"…\", \"…\")`, `message = \"…\"`, `argument_message = \"…\"`, `data(name = value)`, `call = none` or `kind = warning` (error/message/condition also accepted)",
on))
})format!(
178 "unknown `condition` option on {on}; expected `class = \"…\"`, \
179 `class(\"…\", \"…\")`, `message = \"…\"`, `argument_message = \"…\"`, \
180 `data(name = value)`, `call = none` or `kind = warning` \
181 (error/message/condition also accepted)"
182 )));
183 }
184 Ok(())
185 })?;
186 }
187 Ok(out)
188}
189
190#[derive(#[automatically_derived]
impl ::core::default::Default for FieldAttrs {
#[inline]
fn default() -> Self {
FieldAttrs {
skip: ::core::default::Default::default(),
rename: ::core::default::Default::default(),
debug: ::core::default::Default::default(),
skip_none: ::core::default::Default::default(),
}
}
}Default)]
192struct FieldAttrs {
193 skip: bool,
194 rename: Option<syn::LitStr>,
195 debug: bool,
196 skip_none: bool,
198}
199
200fn parse_field_attrs(attrs: &[syn::Attribute]) -> syn::Result<FieldAttrs> {
201 let mut out = FieldAttrs::default();
202 for attr in attrs {
203 if !attr.path().is_ident("condition") {
204 continue;
205 }
206 attr.parse_nested_meta(|meta| {
207 if meta.path.is_ident("skip") {
208 out.skip = true;
209 } else if meta.path.is_ident("debug") {
210 out.debug = true;
211 } else if meta.path.is_ident("skip_none") {
212 out.skip_none = true;
213 } else if meta.path.is_ident("rename") {
214 if out.rename.is_some() {
215 return Err(meta.error("`rename` is given twice"));
216 }
217 out.rename = Some(meta.value()?.parse()?);
218 } else {
219 return Err(meta.error(
220 "unknown `condition` option on a field; expected `skip`, `skip_none`, `debug` \
221 or `rename = \"…\"`",
222 ));
223 }
224 Ok(())
225 })?;
226 }
227 if out.skip && (out.rename.is_some() || out.debug || out.skip_none) {
228 return Err(syn::Error::new(
229 attrs
230 .iter()
231 .find(|a| a.path().is_ident("condition"))
232 .map_or_else(Span::call_site, Spanned::span),
233 "`skip` cannot be combined with `rename`, `debug` or `skip_none`",
234 ));
235 }
236 Ok(out)
237}
238
239struct FieldInfo {
245 binding: syn::Ident,
248 data_name: Option<String>,
250 debug: bool,
252 skip_none: bool,
254}
255
256fn is_option(ty: &syn::Type) -> bool {
258 #[allow(non_exhaustive_omitted_patterns)] match ty {
syn::Type::Path(path) if
path.qself.is_none() &&
path.path.segments.last().is_some_and(|segment|
segment.ident == "Option") => true,
_ => false,
}matches!(ty, syn::Type::Path(path) if path.qself.is_none()
259 && path.path.segments.last().is_some_and(|segment| segment.ident == "Option"))
260}
261
262fn check_data_name(name: &str, seen: &[String], span: Span, context: &str) -> syn::Result<()> {
264 if RESERVED_FIELDS.contains(&name) {
265 return Err(syn::Error::new(
266 span,
267 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}` is one of the condition\'s own slots (`message`, `call`, `kind`); rename the field with `#[condition(rename = \"…\")]` or exclude it with `#[condition(skip)]`",
name))
})format!(
268 "`{name}` is one of the condition's own slots (`message`, `call`, `kind`); \
269 rename the field with `#[condition(rename = \"…\")]` or exclude it with `#[condition(skip)]`"
270 ),
271 ));
272 }
273 if seen.iter().any(|s| s == name) {
274 return Err(syn::Error::new(
275 span,
276 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("duplicate `data` field name `{0}` in {1}",
name, context))
})format!("duplicate `data` field name `{name}` in {context}"),
277 ));
278 }
279 Ok(())
280}
281
282enum Style {
283 Named,
284 Tuple,
285 Unit,
286}
287
288struct Shape<'a> {
291 style: Style,
292 fields: Vec<FieldInfo>,
293 extra: Vec<&'a DataEntry>,
294}
295
296impl<'a> Shape<'a> {
297 fn from_fields(
298 fields: &Fields,
299 extra: Vec<&'a DataEntry>,
300 context: &str,
301 ) -> syn::Result<Shape<'a>> {
302 let (style, iter): (Style, Vec<&syn::Field>) = match fields {
303 Fields::Named(named) => (Style::Named, named.named.iter().collect()),
304 Fields::Unnamed(unnamed) => (Style::Tuple, unnamed.unnamed.iter().collect()),
305 Fields::Unit => (Style::Unit, Vec::new()),
306 };
307 let mut infos = Vec::with_capacity(iter.len());
308 let mut seen: Vec<String> = Vec::new();
309 for (index, field) in iter.iter().enumerate() {
310 let attrs = parse_field_attrs(&field.attrs)?;
311 let binding = match &field.ident {
312 Some(ident) => ident.clone(),
313 None => ::quote::__private::mk_ident(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("_{0}", index))
}),
::quote::__private::Option::Some::<::quote::__private::Span>(field.span()))format_ident!("_{index}", span = field.span()),
314 };
315 let data_name = if attrs.skip {
316 None
317 } else {
318 let name = match (&attrs.rename, &field.ident) {
319 (Some(lit), _) => lit.value(),
320 (None, Some(ident)) => ident_name(ident),
321 (None, None) => {
322 return Err(syn::Error::new(
323 field.span(),
324 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("tuple field {0} of {1} needs a `data` name: add `#[condition(rename = \"name\")]`, or `#[condition(skip)]` to leave it out",
index, context))
})format!(
325 "tuple field {index} of {context} needs a `data` name: add \
326 `#[condition(rename = \"name\")]`, or `#[condition(skip)]` to leave it out"
327 ),
328 ));
329 }
330 };
331 check_data_name(&name, &seen, field.span(), context)?;
332 seen.push(name.clone());
333 Some(name)
334 };
335 if attrs.skip_none && !is_option(&field.ty) {
336 return Err(syn::Error::new(
337 field.ty.span(),
338 "`skip_none` needs an `Option<_>` field: it leaves the entry out when the field is `None`",
339 ));
340 }
341 infos.push(FieldInfo {
342 binding,
343 data_name,
344 debug: attrs.debug,
345 skip_none: attrs.skip_none,
346 });
347 }
348 for entry in &extra {
349 check_data_name(&entry.name, &seen, entry.span, context)?;
350 seen.push(entry.name.clone());
351 }
352 Ok(Shape {
353 style,
354 fields: infos,
355 extra,
356 })
357 }
358
359 fn pattern_all(&self, path: &TokenStream) -> TokenStream {
361 let bindings = self.fields.iter().map(|f| &f.binding);
362 match self.style {
363 Style::Named => {
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&path, &mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
{
use ::quote::__private::ext::*;
let mut _first = true;
let has_iter = ::quote::__private::HasIterator::<false>;
#[allow(unused_mut)]
let (mut bindings, i) = bindings.quote_into_iter();
let has_iter = has_iter | i;
<_ as
::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let bindings =
match bindings.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
if !_first { ::quote::__private::push_comma(&mut _s); }
_first = false;
::quote::ToTokens::to_tokens(&bindings, &mut _s);
}
}
_s
});
_s
}quote! { #path { #(#bindings),* } },
364 Style::Tuple => {
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&path, &mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
{
use ::quote::__private::ext::*;
let mut _first = true;
let has_iter = ::quote::__private::HasIterator::<false>;
#[allow(unused_mut)]
let (mut bindings, i) = bindings.quote_into_iter();
let has_iter = has_iter | i;
<_ as
::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let bindings =
match bindings.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
if !_first { ::quote::__private::push_comma(&mut _s); }
_first = false;
::quote::ToTokens::to_tokens(&bindings, &mut _s);
}
}
_s
});
_s
}quote! { #path ( #(#bindings),* ) },
365 Style::Unit => {
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&path, &mut _s);
_s
}quote! { #path },
366 }
367 }
368
369 fn pattern_data(&self, path: &TokenStream) -> TokenStream {
371 match self.style {
372 Style::Named => {
373 let bindings = self
374 .fields
375 .iter()
376 .filter(|f| f.data_name.is_some())
377 .map(|f| &f.binding);
378 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&path, &mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
{
use ::quote::__private::ext::*;
let has_iter = ::quote::__private::HasIterator::<false>;
#[allow(unused_mut)]
let (mut bindings, i) = bindings.quote_into_iter();
let has_iter = has_iter | i;
<_ as
::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let bindings =
match bindings.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
::quote::ToTokens::to_tokens(&bindings, &mut _s);
::quote::__private::push_comma(&mut _s);
}
}
::quote::__private::push_dot2(&mut _s);
_s
});
_s
}quote! { #path { #(#bindings,)* .. } }
379 }
380 Style::Tuple => {
381 let slots = self.fields.iter().map(|f| {
382 if f.data_name.is_some() {
383 let b = &f.binding;
384 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&b, &mut _s);
_s
}quote! { #b }
385 } else {
386 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_underscore(&mut _s);
_s
}quote! { _ }
387 }
388 });
389 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&path, &mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
{
use ::quote::__private::ext::*;
let mut _first = true;
let has_iter = ::quote::__private::HasIterator::<false>;
#[allow(unused_mut)]
let (mut slots, i) = slots.quote_into_iter();
let has_iter = has_iter | i;
<_ as
::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let slots =
match slots.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
if !_first { ::quote::__private::push_comma(&mut _s); }
_first = false;
::quote::ToTokens::to_tokens(&slots, &mut _s);
}
}
_s
});
_s
}quote! { #path ( #(#slots),* ) }
390 }
391 Style::Unit => {
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&path, &mut _s);
_s
}quote! { #path },
392 }
393 }
394
395 fn pattern_wild(&self, path: &TokenStream) -> TokenStream {
397 match self.style {
398 Style::Unit => {
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&path, &mut _s);
_s
}quote! { #path },
399 Style::Named | Style::Tuple => {
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&path, &mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_dot2(&mut _s);
_s
});
_s
}quote! { #path { .. } },
400 }
401 }
402
403 fn data_expr(&self) -> TokenStream {
406 let value = |f: &FieldInfo, binding: TokenStream| {
407 if f.debug {
408 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "RValue");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "debug");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&binding, &mut _s);
_s
});
_s
}quote! { ::miniextendr_api::RValue::debug(#binding) }
409 } else {
410 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "RValue");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "from");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "core");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "clone");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "Clone");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "clone");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&binding, &mut _s);
_s
});
_s
});
_s
}quote! { ::miniextendr_api::RValue::from(::core::clone::Clone::clone(#binding)) }
411 }
412 };
413 let extra = self.extra.iter().map(|entry| {
414 let name = &entry.name;
415 let expr = &entry.value;
416 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "std");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "string");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "String");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "from");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&name, &mut _s);
_s
});
::quote::__private::push_comma(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "RValue");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "from");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&expr, &mut _s);
_s
});
_s
});
_s
}quote! { (::std::string::String::from(#name), ::miniextendr_api::RValue::from(#expr)) }
417 });
418 if !self
419 .fields
420 .iter()
421 .any(|f| f.skip_none && f.data_name.is_some())
422 {
423 let entries: Vec<TokenStream> = self
424 .fields
425 .iter()
426 .filter_map(|f| {
427 let name = f.data_name.as_ref()?;
428 let binding = &f.binding;
429 let value = value(f, {
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&binding, &mut _s);
_s
}quote! { #binding });
430 Some({
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "std");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "string");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "String");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "from");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&name, &mut _s);
_s
});
::quote::__private::push_comma(&mut _s);
::quote::ToTokens::to_tokens(&value, &mut _s);
_s
});
_s
}quote! { (::std::string::String::from(#name), #value) })
431 })
432 .chain(extra)
433 .collect();
434 return if entries.is_empty() {
435 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "core");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "option");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "Option");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "None");
_s
}quote! { ::core::option::Option::None }
436 } else {
437 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "core");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "option");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "Option");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "Some");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "std");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "vec");
::quote::__private::push_bang(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Bracket,
{
let mut _s = ::quote::__private::TokenStream::new();
{
use ::quote::__private::ext::*;
let mut _first = true;
let has_iter = ::quote::__private::HasIterator::<false>;
#[allow(unused_mut)]
let (mut entries, i) = entries.quote_into_iter();
let has_iter = has_iter | i;
<_ as
::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let entries =
match entries.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
if !_first { ::quote::__private::push_comma(&mut _s); }
_first = false;
::quote::ToTokens::to_tokens(&entries, &mut _s);
}
}
_s
});
_s
});
_s
}quote! { ::core::option::Option::Some(::std::vec![#(#entries),*]) }
438 };
439 }
440 let pushes = self.fields.iter().filter_map(|f| {
443 let name = f.data_name.as_ref()?;
444 let binding = &f.binding;
445 Some(if f.skip_none {
446 let value = value(f, {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "__value");
_s
}quote! { __value });
447 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "if");
::quote::__private::push_ident(&mut _s, "let");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "core");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "option");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "Option");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "Some");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "__value");
_s
});
::quote::__private::push_eq(&mut _s);
::quote::ToTokens::to_tokens(&binding, &mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "__data");
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "push");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "std");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "string");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "String");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "from");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&name, &mut _s);
_s
});
::quote::__private::push_comma(&mut _s);
::quote::ToTokens::to_tokens(&value, &mut _s);
_s
});
_s
});
::quote::__private::push_semi(&mut _s);
_s
});
_s
}quote! {
448 if let ::core::option::Option::Some(__value) = #binding {
449 __data.push((::std::string::String::from(#name), #value));
450 }
451 }
452 } else {
453 let value = value(f, {
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&binding, &mut _s);
_s
}quote! { #binding });
454 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "__data");
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "push");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "std");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "string");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "String");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "from");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&name, &mut _s);
_s
});
::quote::__private::push_comma(&mut _s);
::quote::ToTokens::to_tokens(&value, &mut _s);
_s
});
_s
});
::quote::__private::push_semi(&mut _s);
_s
}quote! { __data.push((::std::string::String::from(#name), #value)); }
455 })
456 });
457 let extra = extra.map(|entry| {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "__data");
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "push");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&entry, &mut _s);
_s
});
::quote::__private::push_semi(&mut _s);
_s
}quote! { __data.push(#entry); });
458 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "let");
::quote::__private::push_ident(&mut _s, "mut");
::quote::__private::push_ident(&mut _s, "__data");
::quote::__private::push_colon(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "condition");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "ConditionData");
::quote::__private::push_eq(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "std");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "vec");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "Vec");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "new");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new());
::quote::__private::push_semi(&mut _s);
{
use ::quote::__private::ext::*;
let has_iter = ::quote::__private::HasIterator::<false>;
#[allow(unused_mut)]
let (mut pushes, i) = pushes.quote_into_iter();
let has_iter = has_iter | i;
<_ as
::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let pushes =
match pushes.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
::quote::ToTokens::to_tokens(&pushes, &mut _s);
}
}
{
use ::quote::__private::ext::*;
let has_iter = ::quote::__private::HasIterator::<false>;
#[allow(unused_mut)]
let (mut extra, i) = extra.quote_into_iter();
let has_iter = has_iter | i;
<_ as
::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let extra =
match extra.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
::quote::ToTokens::to_tokens(&extra, &mut _s);
}
}
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_bang(&mut _s);
::quote::__private::push_ident(&mut _s, "__data");
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "is_empty");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new());
_s
});
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "then_some");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "__data");
_s
});
_s
});
_s
}quote! {{
459 let mut __data: ::miniextendr_api::condition::ConditionData = ::std::vec::Vec::new();
460 #(#pushes)*
461 #(#extra)*
462 (!__data.is_empty()).then_some(__data)
463 }}
464 }
465}
466
467pub fn derive_r_condition(input: DeriveInput) -> syn::Result<TokenStream> {
474 let name = &input.ident;
475 if let Some(param) = input
476 .generics
477 .params
478 .iter()
479 .find(|param| !#[allow(non_exhaustive_omitted_patterns)] match param {
syn::GenericParam::Lifetime(_) => true,
_ => false,
}matches!(param, syn::GenericParam::Lifetime(_)))
480 {
481 return Err(syn::Error::new(
482 param.span(),
483 "`#[derive(RCondition)]` does not support type or const parameters; \
484 lifetime parameters are fine",
485 ));
486 }
487 let container = parse_container_attrs(&input.attrs, "the type")?;
488 derive_condition(&input, name, container)
489}
490
491fn condition_expr(kind: Option<&syn::Ident>) -> TokenStream {
493 let variant = match kind.map(ToString::to_string).as_deref() {
494 Some("error") | None => {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "Error");
_s
}quote! { Error },
495 Some("warning") => {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "Warning");
_s
}quote! { Warning },
496 Some("message") => {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "Message");
_s
}quote! { Message },
497 Some("condition") => {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "Condition");
_s
}quote! { Condition },
498 _ => {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("kind was validated while parsing")));
}unreachable!("kind was validated while parsing"),
499 };
500 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "Self");
::quote::__private::push_colon2(&mut _s);
::quote::ToTokens::to_tokens(&variant, &mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "message");
::quote::__private::push_comma(&mut _s);
::quote::__private::push_ident(&mut _s, "class");
::quote::__private::push_comma(&mut _s);
::quote::__private::push_ident(&mut _s, "data");
::quote::__private::push_comma(&mut _s);
::quote::__private::push_ident(&mut _s, "call");
_s
});
_s
}quote! { Self::#variant { message, class, data, call } }
501}
502
503fn derive_condition(
504 input: &DeriveInput,
505 name: &syn::Ident,
506 container: ContainerAttrs,
507) -> syn::Result<TokenStream> {
508 let default_family = || to_snake_case(&ident_name(name));
509
510 let condition_body;
511 let display = {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "std");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "string");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "ToString");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "to_string");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "self");
_s
});
_s
}quote! { ::std::string::ToString::to_string(self) };
512 let call_none = {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "condition");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "ConditionCall");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "None");
_s
}quote! { ::miniextendr_api::condition::ConditionCall::None };
513
514 let (message_body, class_body, data_body, call_body, argument_message_body) = match &input.data
518 {
519 Data::Struct(data) => {
520 let shape = Shape::from_fields(
521 &data.fields,
522 container.data.iter().collect(),
523 &::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}`", name))
})format!("`{name}`"),
524 )?;
525 condition_body = condition_expr(container.kind.as_ref());
526 let self_path = {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "Self");
_s
}quote! { Self };
527 let message = match &container.message {
528 Some(fmt) => {
529 let pattern = shape.pattern_all(&self_path);
530 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_pound(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Bracket,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "allow");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "unused_variables");
_s
});
_s
});
::quote::__private::push_ident(&mut _s, "let");
::quote::ToTokens::to_tokens(&pattern, &mut _s);
::quote::__private::push_eq(&mut _s);
::quote::__private::push_ident(&mut _s, "self");
::quote::__private::push_semi(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "std");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "format");
::quote::__private::push_bang(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&fmt, &mut _s);
_s
});
_s
}quote! {
531 #[allow(unused_variables)]
532 let #pattern = self;
533 ::std::format!(#fmt)
534 }
535 }
536 None => display.clone(),
537 };
538 let classes: Vec<String> = match &container.class {
539 Some(ClassSpec::One(lit)) => ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[lit.value()]))vec![lit.value()],
540 Some(ClassSpec::List(list, _)) => list.iter().map(syn::LitStr::value).collect(),
541 None => ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[default_family()]))vec![default_family()],
542 };
543 let class = {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "std");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "vec");
::quote::__private::push_bang(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Bracket,
{
let mut _s = ::quote::__private::TokenStream::new();
{
use ::quote::__private::ext::*;
let mut _first = true;
let has_iter = ::quote::__private::HasIterator::<false>;
#[allow(unused_mut)]
let (mut classes, i) = classes.quote_into_iter();
let has_iter = has_iter | i;
<_ as
::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let classes =
match classes.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
if !_first { ::quote::__private::push_comma(&mut _s); }
_first = false;
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "std");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "string");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "String");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "from");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&classes, &mut _s);
_s
});
}
}
_s
});
_s
}quote! { ::std::vec![#(::std::string::String::from(#classes)),*] };
544 let pattern = shape.pattern_data(&self_path);
545 let data_expr = shape.data_expr();
546 let data = {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "let");
::quote::ToTokens::to_tokens(&pattern, &mut _s);
::quote::__private::push_eq(&mut _s);
::quote::__private::push_ident(&mut _s, "self");
::quote::__private::push_semi(&mut _s);
::quote::ToTokens::to_tokens(&data_expr, &mut _s);
_s
}quote! {
547 let #pattern = self;
548 #data_expr
549 };
550 let call = container.call_none.then(|| call_none.clone());
551 let argument_message = container.argument_message.as_ref().map(|fmt| {
552 let pattern = shape.pattern_all(&self_path);
553 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_pound(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Bracket,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "allow");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "unused_variables");
_s
});
_s
});
::quote::__private::push_ident(&mut _s, "let");
::quote::ToTokens::to_tokens(&pattern, &mut _s);
::quote::__private::push_eq(&mut _s);
::quote::__private::push_ident(&mut _s, "self");
::quote::__private::push_semi(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "core");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "option");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "Option");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "Some");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "std");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "format");
::quote::__private::push_bang(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&fmt, &mut _s);
_s
});
_s
});
_s
}quote! {
554 #[allow(unused_variables)]
555 let #pattern = self;
556 ::core::option::Option::Some(::std::format!(#fmt))
557 }
558 });
559 (message, class, data, call, argument_message)
560 }
561 Data::Enum(data) => {
562 if let Some(message) = &container.message {
563 return Err(syn::Error::new(
564 message.span(),
565 "`message` goes on the variants of an enum, not on the enum itself",
566 ));
567 }
568 if let Some(message) = &container.argument_message {
569 return Err(syn::Error::new(
570 message.span(),
571 "`argument_message` goes on the variants of an enum, not on the enum itself",
572 ));
573 }
574 if data.variants.is_empty() {
575 return Err(syn::Error::new(
576 name.span(),
577 "`#[derive(RCondition)]` needs at least one variant",
578 ));
579 }
580 let family = match &container.class {
581 Some(ClassSpec::One(lit)) => lit.value(),
582 Some(ClassSpec::List(_, span)) => {
583 return Err(syn::Error::new(
584 *span,
585 "on an enum, `class(...)` goes on a variant; the enum's \
586 `class = \"…\"` names the family every variant ends with",
587 ));
588 }
589 None => default_family(),
590 };
591 let variant_count = data.variants.len();
592 let mut condition_arms = Vec::new();
593 let mut message_arms = Vec::new();
594 let mut class_arms = Vec::new();
595 let mut data_arms = Vec::new();
596 let mut call_none_arms = Vec::new();
597 let mut argument_message_arms = Vec::new();
598 let mut needs_display = false;
599 for variant in &data.variants {
600 let variant_ident = &variant.ident;
601 let attrs = parse_container_attrs(&variant.attrs, "a variant")?;
602 let members: Vec<String> = match &attrs.class {
603 Some(ClassSpec::One(lit)) => ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[lit.value()]))vec![lit.value()],
604 Some(ClassSpec::List(list, _)) => list.iter().map(syn::LitStr::value).collect(),
605 None => ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{1}_{0}",
to_snake_case(&ident_name(variant_ident)), family))
})]))vec![format!(
606 "{family}_{}",
607 to_snake_case(&ident_name(variant_ident))
608 )],
609 };
610 let shape = Shape::from_fields(
611 &variant.fields,
612 container.data.iter().chain(&attrs.data).collect(),
613 &::alloc::__export::must_use({
::alloc::fmt::format(format_args!("variant `{0}::{1}`", name,
variant_ident))
})format!("variant `{name}::{variant_ident}`"),
614 )?;
615 let pattern = shape.pattern_wild(&{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&name, &mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::ToTokens::to_tokens(&variant_ident, &mut _s);
_s
}quote! { #name::#variant_ident });
616 let expr = condition_expr(attrs.kind.as_ref().or(container.kind.as_ref()));
617 condition_arms.push({
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&pattern, &mut _s);
::quote::__private::push_fat_arrow(&mut _s);
::quote::ToTokens::to_tokens(&expr, &mut _s);
::quote::__private::push_comma(&mut _s);
_s
}quote! { #pattern => #expr, });
618 let path = {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "Self");
::quote::__private::push_colon2(&mut _s);
::quote::ToTokens::to_tokens(&variant_ident, &mut _s);
_s
}quote! { Self::#variant_ident };
619 match &attrs.message {
620 Some(fmt) => {
621 let pattern = shape.pattern_all(&path);
622 message_arms.push({
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_pound(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Bracket,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "allow");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "unused_variables");
_s
});
_s
});
::quote::ToTokens::to_tokens(&pattern, &mut _s);
::quote::__private::push_fat_arrow(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "std");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "format");
::quote::__private::push_bang(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&fmt, &mut _s);
_s
});
::quote::__private::push_comma(&mut _s);
_s
}quote! {
623 #[allow(unused_variables)]
624 #pattern => ::std::format!(#fmt),
625 });
626 }
627 None => needs_display = true,
628 }
629 let wild = shape.pattern_wild(&path);
630 class_arms.push({
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&wild, &mut _s);
::quote::__private::push_fat_arrow(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "std");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "vec");
::quote::__private::push_bang(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Bracket,
{
let mut _s = ::quote::__private::TokenStream::new();
{
use ::quote::__private::ext::*;
let has_iter = ::quote::__private::HasIterator::<false>;
#[allow(unused_mut)]
let (mut members, i) = members.quote_into_iter();
let has_iter = has_iter | i;
<_ as
::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let members =
match members.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "std");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "string");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "String");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "from");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&members, &mut _s);
_s
});
::quote::__private::push_comma(&mut _s);
}
}
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "std");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "string");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "String");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "from");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&family, &mut _s);
_s
});
::quote::__private::push_comma(&mut _s);
_s
});
::quote::__private::push_comma(&mut _s);
_s
}quote! {
631 #wild => ::std::vec![
632 #(::std::string::String::from(#members),)*
633 ::std::string::String::from(#family),
634 ],
635 });
636 let pattern = shape.pattern_data(&path);
637 let data_expr = shape.data_expr();
638 data_arms.push({
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&pattern, &mut _s);
::quote::__private::push_fat_arrow(&mut _s);
::quote::ToTokens::to_tokens(&data_expr, &mut _s);
::quote::__private::push_comma(&mut _s);
_s
}quote! { #pattern => #data_expr, });
639 if let Some(fmt) = &attrs.argument_message {
640 let pattern = shape.pattern_all(&path);
641 argument_message_arms.push({
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_pound(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Bracket,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "allow");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "unused_variables");
_s
});
_s
});
::quote::ToTokens::to_tokens(&pattern, &mut _s);
::quote::__private::push_fat_arrow(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "core");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "option");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "Option");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "Some");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "std");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "format");
::quote::__private::push_bang(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&fmt, &mut _s);
_s
});
_s
});
::quote::__private::push_comma(&mut _s);
_s
}quote! {
642 #[allow(unused_variables)]
643 #pattern => ::core::option::Option::Some(::std::format!(#fmt)),
644 });
645 }
646 if attrs.call_none {
647 call_none_arms.push(wild);
648 }
649 }
650 condition_body = {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "match");
::quote::__private::push_ident(&mut _s, "value");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
{
use ::quote::__private::ext::*;
let has_iter = ::quote::__private::HasIterator::<false>;
#[allow(unused_mut)]
let (mut condition_arms, i) =
condition_arms.quote_into_iter();
let has_iter = has_iter | i;
<_ as
::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let condition_arms =
match condition_arms.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
::quote::ToTokens::to_tokens(&condition_arms, &mut _s);
}
}
_s
});
_s
}quote! { match value { #(#condition_arms)* } };
651 let message = if message_arms.is_empty() {
652 display
653 } else if needs_display {
654 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "match");
::quote::__private::push_ident(&mut _s, "self");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
{
use ::quote::__private::ext::*;
let has_iter = ::quote::__private::HasIterator::<false>;
#[allow(unused_mut)]
let (mut message_arms, i) = message_arms.quote_into_iter();
let has_iter = has_iter | i;
<_ as
::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let message_arms =
match message_arms.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
::quote::ToTokens::to_tokens(&message_arms, &mut _s);
}
}
::quote::__private::push_underscore(&mut _s);
::quote::__private::push_fat_arrow(&mut _s);
::quote::ToTokens::to_tokens(&display, &mut _s);
_s
});
_s
}quote! { match self { #(#message_arms)* _ => #display } }
655 } else {
656 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "match");
::quote::__private::push_ident(&mut _s, "self");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
{
use ::quote::__private::ext::*;
let has_iter = ::quote::__private::HasIterator::<false>;
#[allow(unused_mut)]
let (mut message_arms, i) = message_arms.quote_into_iter();
let has_iter = has_iter | i;
<_ as
::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let message_arms =
match message_arms.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
::quote::ToTokens::to_tokens(&message_arms, &mut _s);
}
}
_s
});
_s
}quote! { match self { #(#message_arms)* } }
657 };
658 let class = {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "match");
::quote::__private::push_ident(&mut _s, "self");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
{
use ::quote::__private::ext::*;
let has_iter = ::quote::__private::HasIterator::<false>;
#[allow(unused_mut)]
let (mut class_arms, i) = class_arms.quote_into_iter();
let has_iter = has_iter | i;
<_ as
::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let class_arms =
match class_arms.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
::quote::ToTokens::to_tokens(&class_arms, &mut _s);
}
}
_s
});
_s
}quote! { match self { #(#class_arms)* } };
659 let data = {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "match");
::quote::__private::push_ident(&mut _s, "self");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
{
use ::quote::__private::ext::*;
let has_iter = ::quote::__private::HasIterator::<false>;
#[allow(unused_mut)]
let (mut data_arms, i) = data_arms.quote_into_iter();
let has_iter = has_iter | i;
<_ as
::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let data_arms =
match data_arms.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
::quote::ToTokens::to_tokens(&data_arms, &mut _s);
}
}
_s
});
_s
}quote! { match self { #(#data_arms)* } };
660 let call = if container.call_none || call_none_arms.len() == variant_count {
661 Some(call_none.clone())
662 } else if call_none_arms.is_empty() {
663 None
664 } else {
665 Some({
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "match");
::quote::__private::push_ident(&mut _s, "self");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
{
use ::quote::__private::ext::*;
let mut _first = true;
let has_iter = ::quote::__private::HasIterator::<false>;
#[allow(unused_mut)]
let (mut call_none_arms, i) =
call_none_arms.quote_into_iter();
let has_iter = has_iter | i;
<_ as
::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let call_none_arms =
match call_none_arms.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
if !_first { ::quote::__private::push_or(&mut _s); }
_first = false;
::quote::ToTokens::to_tokens(&call_none_arms, &mut _s);
}
}
::quote::__private::push_fat_arrow(&mut _s);
::quote::ToTokens::to_tokens(&call_none, &mut _s);
::quote::__private::push_comma(&mut _s);
::quote::__private::push_underscore(&mut _s);
::quote::__private::push_fat_arrow(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "condition");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "ConditionCall");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "Inherit");
::quote::__private::push_comma(&mut _s);
_s
});
_s
}quote! {
666 match self {
667 #(#call_none_arms)|* => #call_none,
668 _ => ::miniextendr_api::condition::ConditionCall::Inherit,
669 }
670 })
671 };
672 let argument_message = if argument_message_arms.is_empty() {
673 None
674 } else if argument_message_arms.len() == variant_count {
675 Some({
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "match");
::quote::__private::push_ident(&mut _s, "self");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
{
use ::quote::__private::ext::*;
let has_iter = ::quote::__private::HasIterator::<false>;
#[allow(unused_mut)]
let (mut argument_message_arms, i) =
argument_message_arms.quote_into_iter();
let has_iter = has_iter | i;
<_ as
::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let argument_message_arms =
match argument_message_arms.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
::quote::ToTokens::to_tokens(&argument_message_arms,
&mut _s);
}
}
_s
});
_s
}quote! { match self { #(#argument_message_arms)* } })
676 } else {
677 Some({
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_pound(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Bracket,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "allow");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s,
"unreachable_patterns");
_s
});
_s
});
::quote::__private::push_ident(&mut _s, "match");
::quote::__private::push_ident(&mut _s, "self");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
{
use ::quote::__private::ext::*;
let has_iter = ::quote::__private::HasIterator::<false>;
#[allow(unused_mut)]
let (mut argument_message_arms, i) =
argument_message_arms.quote_into_iter();
let has_iter = has_iter | i;
<_ as
::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let argument_message_arms =
match argument_message_arms.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
::quote::ToTokens::to_tokens(&argument_message_arms,
&mut _s);
}
}
::quote::__private::push_underscore(&mut _s);
::quote::__private::push_fat_arrow(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "core");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "option");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "Option");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "None");
::quote::__private::push_comma(&mut _s);
_s
});
_s
}quote! {
678 #[allow(unreachable_patterns)]
679 match self {
680 #(#argument_message_arms)*
681 _ => ::core::option::Option::None,
682 }
683 })
684 };
685 (message, class, data, call, argument_message)
686 }
687 Data::Union(_) => {
688 return Err(syn::Error::new(
689 name.span(),
690 "`#[derive(RCondition)]` supports structs and enums, not unions",
691 ));
692 }
693 };
694
695 let call_method = call_body.map(|body| {
696 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "fn");
::quote::__private::push_ident(&mut _s, "call");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_and(&mut _s);
::quote::__private::push_ident(&mut _s, "self");
_s
});
::quote::__private::push_rarrow(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "condition");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "ConditionCall");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&body, &mut _s);
_s
});
_s
}quote! {
697 fn call(&self) -> ::miniextendr_api::condition::ConditionCall {
698 #body
699 }
700 }
701 });
702 let argument_message_method = argument_message_body.map(|body| {
703 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "fn");
::quote::__private::push_ident(&mut _s, "argument_message");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_and(&mut _s);
::quote::__private::push_ident(&mut _s, "self");
_s
});
::quote::__private::push_rarrow(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "core");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "option");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "Option");
::quote::__private::push_lt(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "std");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "string");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "String");
::quote::__private::push_gt(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&body, &mut _s);
_s
});
_s
}quote! {
704 fn argument_message(&self) -> ::core::option::Option<::std::string::String> {
705 #body
706 }
707 }
708 });
709
710 let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
711 Ok({
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_pound(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Bracket,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "automatically_derived");
_s
});
::quote::__private::push_ident(&mut _s, "impl");
::quote::ToTokens::to_tokens(&impl_generics, &mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "core");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "convert");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "From");
::quote::__private::push_lt(&mut _s);
::quote::ToTokens::to_tokens(&name, &mut _s);
::quote::ToTokens::to_tokens(&ty_generics, &mut _s);
::quote::__private::push_gt(&mut _s);
::quote::__private::push_ident(&mut _s, "for");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "condition");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "RCondition");
::quote::ToTokens::to_tokens(&where_clause, &mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "fn");
::quote::__private::push_ident(&mut _s, "from");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "value");
::quote::__private::push_colon(&mut _s);
::quote::ToTokens::to_tokens(&name, &mut _s);
::quote::ToTokens::to_tokens(&ty_generics, &mut _s);
_s
});
::quote::__private::push_rarrow(&mut _s);
::quote::__private::push_ident(&mut _s, "Self");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "let");
::quote::__private::push_ident(&mut _s, "message");
::quote::__private::push_eq(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "condition");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "RConditionData");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "message");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_and(&mut _s);
::quote::__private::push_ident(&mut _s, "value");
_s
});
::quote::__private::push_semi(&mut _s);
::quote::__private::push_ident(&mut _s, "let");
::quote::__private::push_ident(&mut _s, "class");
::quote::__private::push_eq(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "condition");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "RConditionData");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "class");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_and(&mut _s);
::quote::__private::push_ident(&mut _s, "value");
_s
});
::quote::__private::push_semi(&mut _s);
::quote::__private::push_ident(&mut _s, "let");
::quote::__private::push_ident(&mut _s, "data");
::quote::__private::push_eq(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "condition");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "RConditionData");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "data");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_and(&mut _s);
::quote::__private::push_ident(&mut _s, "value");
_s
});
::quote::__private::push_semi(&mut _s);
::quote::__private::push_ident(&mut _s, "let");
::quote::__private::push_ident(&mut _s, "call");
::quote::__private::push_eq(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "condition");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "RConditionData");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "call");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_and(&mut _s);
::quote::__private::push_ident(&mut _s, "value");
_s
});
::quote::__private::push_semi(&mut _s);
::quote::ToTokens::to_tokens(&condition_body, &mut _s);
_s
});
_s
});
::quote::__private::push_pound(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Bracket,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "automatically_derived");
_s
});
::quote::__private::push_ident(&mut _s, "impl");
::quote::ToTokens::to_tokens(&impl_generics, &mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "condition");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "RConditionData");
::quote::__private::push_ident(&mut _s, "for");
::quote::ToTokens::to_tokens(&name, &mut _s);
::quote::ToTokens::to_tokens(&ty_generics, &mut _s);
::quote::ToTokens::to_tokens(&where_clause, &mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "fn");
::quote::__private::push_ident(&mut _s, "message");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_and(&mut _s);
::quote::__private::push_ident(&mut _s, "self");
_s
});
::quote::__private::push_rarrow(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "std");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "string");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "String");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&message_body, &mut _s);
_s
});
::quote::__private::push_ident(&mut _s, "fn");
::quote::__private::push_ident(&mut _s, "class");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_and(&mut _s);
::quote::__private::push_ident(&mut _s, "self");
_s
});
::quote::__private::push_rarrow(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "std");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "vec");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "Vec");
::quote::__private::push_lt(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "std");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "string");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "String");
::quote::__private::push_gt(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&class_body, &mut _s);
_s
});
::quote::__private::push_ident(&mut _s, "fn");
::quote::__private::push_ident(&mut _s, "data");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_and(&mut _s);
::quote::__private::push_ident(&mut _s, "self");
::quote::__private::push_comma(&mut _s);
_s
});
::quote::__private::push_rarrow(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "core");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "option");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "Option");
::quote::__private::push_lt(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "condition");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "ConditionData");
::quote::__private::push_gt(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&data_body, &mut _s);
_s
});
::quote::ToTokens::to_tokens(&call_method, &mut _s);
::quote::ToTokens::to_tokens(&argument_message_method, &mut _s);
_s
});
_s
}quote! {
712 #[automatically_derived]
713 impl #impl_generics ::core::convert::From<#name #ty_generics>
714 for ::miniextendr_api::condition::RCondition #where_clause
715 {
716 fn from(value: #name #ty_generics) -> Self {
717 let message = ::miniextendr_api::condition::RConditionData::message(&value);
718 let class = ::miniextendr_api::condition::RConditionData::class(&value);
719 let data = ::miniextendr_api::condition::RConditionData::data(&value);
720 let call = ::miniextendr_api::condition::RConditionData::call(&value);
721 #condition_body
722 }
723 }
724
725 #[automatically_derived]
726 impl #impl_generics ::miniextendr_api::condition::RConditionData
727 for #name #ty_generics #where_clause
728 {
729 fn message(&self) -> ::std::string::String {
730 #message_body
731 }
732
733 fn class(&self) -> ::std::vec::Vec<::std::string::String> {
734 #class_body
735 }
736
737 fn data(
738 &self,
739 ) -> ::core::option::Option<::miniextendr_api::condition::ConditionData> {
740 #data_body
741 }
742
743 #call_method
744
745 #argument_message_method
746 }
747 })
748}
749
750#[cfg(test)]
755mod tests {
756 use super::*;
757
758 fn derive(input: DeriveInput) -> String {
759 derive_r_condition(input).unwrap().to_string()
760 }
761
762 fn derive_err(input: DeriveInput) -> String {
763 derive_r_condition(input).unwrap_err().to_string()
764 }
765
766 #[test]
767 fn condition_rejects_invalid_and_duplicate_kinds() {
768 for input in [
769 syn::parse_quote! {
770 #[condition(kind = panic)]
771 struct Invalid;
772 },
773 syn::parse_quote! {
774 #[condition(kind = warning, kind = error)]
775 struct Duplicate;
776 },
777 syn::parse_quote! {
778 enum InvalidVariant {
779 #[condition(kind = conversion)]
780 Bad,
781 }
782 },
783 ] {
784 assert!(derive_r_condition(input).is_err());
785 }
786 }
787
788 #[test]
789 fn kind_defaults_to_error_and_a_variant_overrides_the_type() {
790 let code = derive(syn::parse_quote! {
791 struct Plain;
792 });
793 assert!(code.contains("Self :: Error { message , class , data , call }"));
794 let code = derive(syn::parse_quote! {
795 #[condition(kind = warning)]
796 enum Mixed {
797 #[condition(kind = message)]
798 Note,
799 #[condition(kind = error)]
800 Fatal,
801 Drift,
802 }
803 });
804 assert!(code.contains("Mixed :: Note => Self :: Message"));
805 assert!(code.contains("Mixed :: Fatal => Self :: Error"));
806 assert!(code.contains("Mixed :: Drift => Self :: Warning"));
807 }
808
809 #[test]
810 fn enum_classes_default_to_snake_case_family_and_member() {
811 let code = derive(syn::parse_quote! {
812 enum PkgError {
813 MissingField { field: String },
814 OutOfRange { value: f64, max: f64 },
815 Plain,
816 }
817 });
818 assert!(code.contains("\"pkg_error_missing_field\""));
819 assert!(code.contains("\"pkg_error_out_of_range\""));
820 assert!(code.contains("\"pkg_error_plain\""));
821 assert!(code.contains("\"pkg_error\""));
822 assert!(code.contains("ToString :: to_string (self)"));
824 assert!(!code.contains("format !"));
825 assert!(code.contains("\"field\""));
827 assert!(code.contains("\"max\""));
828 assert!(code.contains("Clone :: clone (max)"));
829 }
830
831 #[test]
832 fn explicit_classes_messages_and_field_options() {
833 let code = derive(syn::parse_quote! {
834 #[condition(class = "pkg_warning")]
835 enum PkgWarning {
836 #[condition(message = "dropped {dropped} of {total} rows")]
837 Truncated { dropped: i32, total: i32 },
838 #[condition(class = "pkg_warning_slow_path", message = "slow")]
839 Slow,
840 Other {
841 #[condition(rename = "n_attempts")]
842 attempts: i32,
843 #[condition(debug)]
844 range: std::ops::Range<i32>,
845 #[condition(skip)]
846 detail: Vec<u8>,
847 },
848 }
849 });
850 assert!(code.contains("\"pkg_warning_truncated\""));
851 assert!(code.contains("\"pkg_warning_slow_path\""));
852 assert!(code.contains("\"pkg_warning_other\""));
853 assert!(code.contains("format ! (\"dropped {dropped} of {total} rows\")"));
854 assert!(code.contains("_ => :: std :: string :: ToString :: to_string (self)"));
856 assert!(code.contains("\"n_attempts\""));
857 assert!(!code.contains("\"attempts\""));
858 assert!(code.contains("RValue :: debug (range)"));
859 assert!(!code.contains("\"detail\""));
860 assert!(code.contains("Self :: Other { attempts , range , .. } =>"));
862 }
863
864 #[test]
865 fn struct_shapes() {
866 let named = derive(syn::parse_quote! {
867 #[condition(message = "took {attempts} attempts")]
868 struct RetryNotice {
869 attempts: i32,
870 }
871 });
872 assert!(named.contains("\"retry_notice\""));
873 assert!(named.contains("let Self { attempts } = self"));
874 assert!(named.contains("format ! (\"took {attempts} attempts\")"));
875
876 let tuple = derive(syn::parse_quote! {
877 struct Pair(#[condition(rename = "left")] i32, #[condition(skip)] String);
878 });
879 assert!(tuple.contains("\"left\""));
880 assert!(tuple.contains("Self (_0 , _)"));
881
882 let unit = derive(syn::parse_quote! {
883 struct Nothing;
884 });
885 assert!(unit.contains("Option :: None"));
886 assert!(unit.contains("\"nothing\""));
887 }
888
889 #[test]
890 fn call_none_on_the_type_or_a_variant() {
891 let code = derive(syn::parse_quote! {
893 #[condition(class = "pkg_warning")]
894 enum PkgWarning {
895 #[condition(call = none, message = "row {row} overrides an earlier one")]
896 Overridden { row: i32 },
897 Truncated { dropped: i32 },
898 }
899 });
900 assert!(code.contains("fn call (& self)"));
901 assert!(code.contains(
902 "Self :: Overridden { .. } => :: miniextendr_api :: condition :: ConditionCall :: None"
903 ));
904 assert!(code.contains("_ => :: miniextendr_api :: condition :: ConditionCall :: Inherit"));
905
906 for code in [
908 derive(syn::parse_quote! {
909 #[condition(call = none)]
910 enum E { A, B { n: i32 } }
911 }),
912 derive(syn::parse_quote! {
913 enum E {
914 #[condition(call = none)]
915 A,
916 #[condition(call = none)]
917 B { n: i32 },
918 }
919 }),
920 derive(syn::parse_quote! {
921 #[condition(call = none, message = "plain")]
922 struct Notice;
923 }),
924 ] {
925 assert!(code.contains("fn call (& self) -> :: miniextendr_api :: condition :: ConditionCall { :: miniextendr_api :: condition :: ConditionCall :: None }"), "{code}");
926 }
927
928 let code = derive(syn::parse_quote! {
930 enum E { A, B }
931 });
932 assert!(!code.contains("fn call"));
933 }
934
935 #[test]
936 fn rejects_bad_call_values() {
937 let err = derive_err(syn::parse_quote! {
938 #[condition(call = wrapper)]
939 struct S;
940 });
941 assert!(err.contains("unknown `call` value `wrapper`"), "{err}");
942
943 let err = derive_err(syn::parse_quote! {
944 #[condition(call = "none")]
945 struct S;
946 });
947 assert!(err.contains("`call` takes `none`"), "{err}");
948
949 let err = derive_err(syn::parse_quote! {
950 enum E {
951 #[condition(call = none, call = none)]
952 A,
953 }
954 });
955 assert!(err.contains("`call` is given twice"), "{err}");
956
957 let err = derive_err(syn::parse_quote! {
958 struct S {
959 #[condition(call = none)]
960 a: i32,
961 }
962 });
963 assert!(
964 err.contains("unknown `condition` option on a field"),
965 "{err}"
966 );
967 }
968
969 #[test]
970 fn rejects_type_and_const_parameters_and_unions() {
971 let err = derive_err(syn::parse_quote! {
972 struct Generic<T> {
973 value: T,
974 }
975 });
976 assert!(err.contains("type or const parameters"), "{err}");
977
978 let err = derive_err(syn::parse_quote! {
979 struct Sized<'a, const N: usize> {
980 value: &'a [i32; N],
981 }
982 });
983 assert!(err.contains("type or const parameters"), "{err}");
984
985 let err = derive_err(syn::parse_quote! {
986 union U {
987 a: u32,
988 b: f32,
989 }
990 });
991 assert!(err.contains("not unions"));
992 }
993
994 #[test]
995 fn rejects_unnamed_tuple_fields_and_reserved_or_duplicate_names() {
996 let err = derive_err(syn::parse_quote! {
997 enum E {
998 Raw(i32),
999 }
1000 });
1001 assert!(err.contains("tuple field 0 of variant `E::Raw` needs a `data` name"));
1002
1003 let err = derive_err(syn::parse_quote! {
1004 struct S {
1005 kind: String,
1006 }
1007 });
1008 assert!(err.contains("`kind` is one of the condition's own slots"));
1009
1010 let err = derive_err(syn::parse_quote! {
1011 struct S {
1012 #[condition(rename = "message")]
1013 text: String,
1014 }
1015 });
1016 assert!(err.contains("`message` is one of the condition's own slots"));
1017
1018 let err = derive_err(syn::parse_quote! {
1019 struct S {
1020 a: i32,
1021 #[condition(rename = "a")]
1022 b: i32,
1023 }
1024 });
1025 assert!(err.contains("duplicate `data` field name `a`"));
1026 }
1027
1028 #[test]
1029 fn rejects_misplaced_or_unknown_options() {
1030 let err = derive_err(syn::parse_quote! {
1031 #[condition(message = "nope")]
1032 enum E {
1033 A,
1034 }
1035 });
1036 assert!(err.contains("goes on the variants"));
1037
1038 let err = derive_err(syn::parse_quote! {
1039 #[condition(prefix = "x")]
1040 struct S {
1041 a: i32,
1042 }
1043 });
1044 assert!(err.contains("unknown `condition` option on the type"));
1045
1046 let err = derive_err(syn::parse_quote! {
1047 struct S {
1048 #[condition(class = "x")]
1049 a: i32,
1050 }
1051 });
1052 assert!(err.contains("unknown `condition` option on a field"));
1053
1054 let err = derive_err(syn::parse_quote! {
1055 struct S {
1056 #[condition(skip, rename = "b")]
1057 a: i32,
1058 }
1059 });
1060 assert!(err.contains("`skip` cannot be combined"));
1061
1062 let err = derive_err(syn::parse_quote! {
1063 enum Empty {}
1064 });
1065 assert!(err.contains("at least one variant"));
1066
1067 let err = derive_err(syn::parse_quote! {
1068 #[condition(argument_message = "nope")]
1069 enum E {
1070 A,
1071 }
1072 });
1073 assert!(
1074 err.contains("`argument_message` goes on the variants"),
1075 "{err}"
1076 );
1077
1078 let err = derive_err(syn::parse_quote! {
1079 #[condition(argument_message = "a", argument_message = "b")]
1080 struct S;
1081 });
1082 assert!(err.contains("`argument_message` is given twice"), "{err}");
1083 }
1084
1085 #[test]
1089 fn argument_message_on_a_struct_or_on_variants() {
1090 let code = derive(syn::parse_quote! {
1091 #[condition(argument_message = "use model_from_df() for a {what}")]
1092 struct ModelRefused {
1093 what: String,
1094 }
1095 });
1096 assert!(code.contains("fn argument_message (& self)"), "{code}");
1097 assert!(
1098 code.contains("Some (:: std :: format ! (\"use model_from_df() for a {what}\"))"),
1099 "{code}"
1100 );
1101
1102 let code = derive(syn::parse_quote! {
1103 enum Refused {
1104 #[condition(argument_message = "use model_from_df() for a data frame")]
1105 DataFrame,
1106 Other { class: String },
1107 }
1108 });
1109 assert!(code.contains("fn argument_message (& self)"), "{code}");
1110 assert!(
1111 code.contains("_ => :: core :: option :: Option :: None"),
1112 "{code}"
1113 );
1114
1115 let code = derive(syn::parse_quote! {
1116 struct Plain;
1117 });
1118 assert!(!code.contains("fn argument_message"), "{code}");
1119 }
1120
1121 #[test]
1122 fn lifetime_parameters_reach_both_impls() {
1123 let code = derive(syn::parse_quote! {
1124 #[condition(class = "pkg_engine_warning")]
1125 struct EngineWarning<'a>(#[condition(skip)] &'a str);
1126 });
1127 assert!(
1128 code.contains("impl < 'a > :: core :: convert :: From < EngineWarning < 'a > >"),
1129 "{code}"
1130 );
1131 assert!(
1132 code.contains("fn from (value : EngineWarning < 'a >)"),
1133 "{code}"
1134 );
1135 assert!(
1136 code.contains("RConditionData for EngineWarning < 'a >"),
1137 "{code}"
1138 );
1139 }
1140
1141 #[test]
1142 fn class_list_on_a_struct_is_its_whole_class_vector() {
1143 let code = derive(syn::parse_quote! {
1144 #[condition(class("pkg_message_selection_dropped", "pkg_message"))]
1145 struct SelectionDropped {
1146 missing: Vec<String>,
1147 }
1148 });
1149 assert!(
1150 code.contains(
1151 r#"vec ! [:: std :: string :: String :: from ("pkg_message_selection_dropped") , :: std :: string :: String :: from ("pkg_message")]"#
1152 ),
1153 "{code}"
1154 );
1155 }
1156
1157 #[test]
1158 fn class_list_on_a_variant_replaces_the_member() {
1159 let code = derive(syn::parse_quote! {
1160 #[condition(class = "pkg_warning")]
1161 enum PkgWarning {
1162 #[condition(class("pkg_warning_engine_masked", "pkg_engine_warning"))]
1163 Masked,
1164 Plain,
1165 }
1166 });
1167 assert!(
1168 code.contains(
1169 r#"Self :: Masked => :: std :: vec ! [:: std :: string :: String :: from ("pkg_warning_engine_masked") , :: std :: string :: String :: from ("pkg_engine_warning") , :: std :: string :: String :: from ("pkg_warning") ,]"#
1170 ),
1171 "{code}"
1172 );
1173 assert!(code.contains(r#""pkg_warning_plain""#), "{code}");
1174 }
1175
1176 #[test]
1177 fn class_list_errors() {
1178 let err = derive_err(syn::parse_quote! {
1179 #[condition(class("a", "b"))]
1180 enum E {
1181 One,
1182 }
1183 });
1184 assert!(
1185 err.contains("on an enum, `class(...)` goes on a variant"),
1186 "{err}"
1187 );
1188
1189 let err = derive_err(syn::parse_quote! {
1190 #[condition(class())]
1191 struct S;
1192 });
1193 assert!(err.contains("needs at least one class"), "{err}");
1194
1195 let err = derive_err(syn::parse_quote! {
1196 #[condition(class = "a", class("b"))]
1197 struct S;
1198 });
1199 assert!(err.contains("`class` is given twice"), "{err}");
1200 }
1201
1202 #[test]
1203 fn data_entries_follow_the_fields() {
1204 let code = derive(syn::parse_quote! {
1205 #[condition(class = "pkg_warning", data(param = "unit_table"))]
1206 struct UnitTableIgnored;
1207 });
1208 assert!(
1209 code.contains(
1210 r#"Some (:: std :: vec ! [(:: std :: string :: String :: from ("param") , :: miniextendr_api :: RValue :: from ("unit_table"))])"#
1211 ),
1212 "{code}"
1213 );
1214
1215 let code = derive(syn::parse_quote! {
1217 #[condition(data(source = "engine"))]
1218 enum E {
1219 #[condition(data(r#type = 2i32))]
1220 One { n: i32 },
1221 }
1222 });
1223 let n = code.find(r#""n""#).expect("field entry");
1224 let source = code.find(r#""source""#).expect("type entry");
1225 let ty = code.find(r#""type""#).expect("variant entry");
1226 assert!(n < source && source < ty, "{code}");
1227 }
1228
1229 #[test]
1230 fn data_entry_names_are_checked_like_fields() {
1231 let err = derive_err(syn::parse_quote! {
1232 #[condition(data(kind = "x"))]
1233 struct S;
1234 });
1235 assert!(
1236 err.contains("`kind` is one of the condition's own slots"),
1237 "{err}"
1238 );
1239
1240 let err = derive_err(syn::parse_quote! {
1241 #[condition(data(n = 1i32))]
1242 struct S {
1243 n: i32,
1244 }
1245 });
1246 assert!(err.contains("duplicate `data` field name `n`"), "{err}");
1247
1248 let err = derive_err(syn::parse_quote! {
1249 #[condition(data(a::b = 1i32))]
1250 struct S;
1251 });
1252 assert!(err.contains("a `data` entry is `name = value`"), "{err}");
1253 }
1254
1255 #[test]
1256 fn skip_none_leaves_a_none_entry_out() {
1257 let code = derive(syn::parse_quote! {
1258 struct Masked {
1259 verb: String,
1260 #[condition(skip_none)]
1261 given_to: Option<String>,
1262 }
1263 });
1264 assert!(
1265 code.contains("if let :: core :: option :: Option :: Some (__value) = given_to"),
1266 "{code}"
1267 );
1268 assert!(
1269 code.contains("(! __data . is_empty ()) . then_some (__data)"),
1270 "{code}"
1271 );
1272 assert!(
1274 code.contains(r#"__data . push ((:: std :: string :: String :: from ("verb")"#),
1275 "{code}"
1276 );
1277 }
1278
1279 #[test]
1280 fn skip_none_errors() {
1281 let err = derive_err(syn::parse_quote! {
1282 struct S {
1283 #[condition(skip_none)]
1284 n: i32,
1285 }
1286 });
1287 assert!(
1288 err.contains("`skip_none` needs an `Option<_>` field"),
1289 "{err}"
1290 );
1291
1292 let err = derive_err(syn::parse_quote! {
1293 struct S {
1294 #[condition(skip, skip_none)]
1295 n: Option<i32>,
1296 }
1297 });
1298 assert!(
1299 err.contains("`skip` cannot be combined with `rename`, `debug` or `skip_none`"),
1300 "{err}"
1301 );
1302 }
1303}
1304
1305