xso_proc/
state.rs

1// Copyright (c) 2024 Jonas Schäfer <jonas@zombofant.net>
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7//! State machines for parsing and serialising of structs and enums.
8
9use proc_macro2::TokenStream;
10use quote::{quote, ToTokens};
11use syn::*;
12
13/// A single state in a parser or serializer state machine.
14pub(crate) struct State {
15    /// Name of the state enum variant for this state.
16    name: Ident,
17
18    /// Declaration of members of the state enum in this state.
19    decl: TokenStream,
20
21    /// Destructuring of members of the state enum in this state.
22    destructure: TokenStream,
23
24    /// Right-hand-side of the match arm for this state.
25    advance_body: TokenStream,
26
27    /// If set, that identifier will be bound mutably.
28    uses_mut: Option<Ident>,
29}
30
31impl State {
32    /// Create a new state with the a builder data field.
33    ///
34    /// This is a convenience wrapper around `new()` and `add_field()`. This
35    /// wrapper, or its equivalent, **must** be used for states used in
36    /// [`FromEventsStateMachine`] state machines, as those expect that the
37    /// first field is the builder data at render time.
38    pub(crate) fn new_with_builder(
39        name: Ident,
40        builder_data_ident: &Ident,
41        builder_data_ty: &Type,
42    ) -> Self {
43        let mut result = Self::new(name);
44        result.add_field(builder_data_ident, builder_data_ty);
45        result
46    }
47
48    /// Create a new, empty state.
49    ///
50    /// Note that an empty state will generate invalid code. At the very
51    /// least, a body must be added using [`Self::set_impl`] or
52    /// [`Self::with_impl`]. The various state machines may also have
53    /// additional requirements.
54    pub(crate) fn new(name: Ident) -> Self {
55        Self {
56            name,
57            decl: TokenStream::default(),
58            destructure: TokenStream::default(),
59            advance_body: TokenStream::default(),
60            uses_mut: None,
61        }
62    }
63
64    /// Add a field to this state's data.
65    ///
66    /// - `name` is the name under which the data will be accessible in the
67    ///   state's implementation.
68    /// - `ty` must be the data field's type.
69    pub(crate) fn add_field(&mut self, name: &Ident, ty: &Type) {
70        self.decl.extend(quote! { #name: #ty, });
71        self.destructure.extend(quote! { #name, });
72    }
73
74    /// Modify the state to include another field and return the modified
75    /// state.
76    ///
77    /// This is a consume-and-return-style version of [`Self::add_field`].
78    pub(crate) fn with_field(mut self, name: &Ident, ty: &Type) -> Self {
79        self.add_field(name, ty);
80        self
81    }
82
83    /// Set the `advance` implementation of this state.
84    ///
85    /// `body` must be the body of the right hand side of the match arm for
86    /// the `advance` implementation of the state machine.
87    ///
88    /// See [`FromEventsStateMachine::advance_match_arms`] and
89    /// [`AsItemsSubmachine::compile`] for the respective
90    /// requirements on the implementations.
91    pub(crate) fn with_impl(mut self, body: TokenStream) -> Self {
92        self.advance_body = body;
93        self
94    }
95
96    /// Override the current `advance` implementation of this state.
97    ///
98    /// This is an in-place version of [`Self::with_impl`].
99    pub(crate) fn set_impl(&mut self, body: TokenStream) {
100        self.advance_body = body;
101    }
102
103    /// Modify the state to mark the given field as mutable and return the
104    /// modified state.
105    pub(crate) fn with_mut(mut self, ident: &Ident) -> Self {
106        assert!(self.uses_mut.is_none());
107        self.uses_mut = Some(ident.clone());
108        self
109    }
110}
111
112/// A partial [`FromEventsStateMachine`] which only covers the builder for a
113/// single compound.
114///
115/// See [`FromEventsStateMachine`] for more information on the state machines
116/// in general.
117pub(crate) struct FromEventsSubmachine {
118    /// Additional items necessary for the statemachine.
119    pub(crate) defs: TokenStream,
120
121    /// States and state transition implementations.
122    pub(crate) states: Vec<State>,
123
124    /// Initializer expression.
125    ///
126    /// This expression must evaluate to a
127    /// `Result<#state_ty_ident, xso::FromEventsError>`.
128    pub(crate) init: TokenStream,
129}
130
131impl FromEventsSubmachine {
132    /// Convert a partial state machine into a full state machine.
133    ///
134    /// This converts the abstract [`State`] items into token
135    /// streams for the respective parts of the state machine (the state
136    /// definitions and the match arms), rendering them effectively immutable.
137    pub(crate) fn compile(self) -> FromEventsStateMachine {
138        let mut state_defs = TokenStream::default();
139        let mut advance_match_arms = TokenStream::default();
140
141        for state in self.states {
142            let State {
143                name,
144                decl,
145                destructure,
146                advance_body,
147                uses_mut,
148            } = state;
149
150            state_defs.extend(quote! {
151                #name { #decl },
152            });
153
154            let binding = if let Some(uses_mut) = uses_mut.as_ref() {
155                quote! {
156                    let mut #uses_mut = #uses_mut;
157                }
158            } else {
159                TokenStream::default()
160            };
161
162            // XXX: nasty hack, but works: the first member of the enum always
163            // exists and it always is the builder data, which we always need
164            // mutably available. So we can just prefix the destructuring
165            // token stream with `mut` to make that first member mutable.
166            advance_match_arms.extend(quote! {
167                Self::#name { mut #destructure } => {
168                    #binding
169                    #advance_body
170                }
171            });
172        }
173
174        FromEventsStateMachine {
175            defs: self.defs,
176            state_defs,
177            advance_match_arms,
178            variants: vec![FromEventsEntryPoint { init: self.init }],
179            pre_init: TokenStream::default(),
180            fallback: None,
181        }
182    }
183
184    /// Update the [`init`][`Self::init`] field in-place.
185    ///
186    /// The function will receive a reference to the current `init` value,
187    /// allowing to create "wrappers" around that existing code.
188    pub(crate) fn with_augmented_init<F: FnOnce(&TokenStream) -> TokenStream>(
189        mut self,
190        f: F,
191    ) -> Self {
192        let new_init = f(&self.init);
193        self.init = new_init;
194        self
195    }
196}
197
198/// A partial [`AsItemsStateMachine`] which only covers the builder for a
199/// single compound.
200///
201/// See [`AsItemsStateMachine`] for more information on the state machines
202/// in general.
203pub(crate) struct AsItemsSubmachine {
204    /// Additional items necessary for the statemachine.
205    pub(crate) defs: TokenStream,
206
207    /// States and state transition implementations.
208    pub(crate) states: Vec<State>,
209
210    /// A pattern match which destructures the target type into its parts, for
211    /// use by `init`.
212    pub(crate) destructure: TokenStream,
213
214    /// An expression which uses the names bound in `destructure` to create a
215    /// an instance of the state enum.
216    ///
217    /// The state enum type is available as `Self` in that context.
218    pub(crate) init: TokenStream,
219}
220
221impl AsItemsSubmachine {
222    /// Convert a partial state machine into a full state machine.
223    ///
224    /// This converts the abstract [`State`] items into token
225    /// streams for the respective parts of the state machine (the state
226    /// definitions and the match arms), rendering them effectively immutable.
227    ///
228    /// This requires that the [`State::advance_body`] token streams evaluate
229    /// to an `Option<Item>`. If it evaluates to `Some(.)`, that is
230    /// emitted from the iterator. If it evaluates to `None`, the `advance`
231    /// implementation is called again.
232    ///
233    /// Each state implementation is augmented to also enter the next state,
234    /// causing the iterator to terminate eventually.
235    pub(crate) fn compile(self) -> AsItemsStateMachine {
236        let mut state_defs = TokenStream::default();
237        let mut advance_match_arms = TokenStream::default();
238
239        for (i, state) in self.states.iter().enumerate() {
240            let State {
241                ref name,
242                ref decl,
243                ref destructure,
244                ref advance_body,
245                ref uses_mut,
246            } = state;
247
248            let footer = match self.states.get(i + 1) {
249                Some(State {
250                    name: ref next_name,
251                    destructure: ref construct_next,
252                    ..
253                }) => {
254                    quote! {
255                        ::core::result::Result::Ok((::core::option::Option::Some(Self::#next_name { #construct_next }), item))
256                    }
257                }
258                // final state -> exit the state machine
259                None => {
260                    quote! {
261                        ::core::result::Result::Ok((::core::option::Option::None, item))
262                    }
263                }
264            };
265
266            state_defs.extend(quote! {
267                #name { #decl },
268            });
269
270            if let Some(uses_mut) = uses_mut.as_ref() {
271                // the variant is non-consuming, meaning it can be called
272                // multiple times and it uses the identifier in `uses_mut`
273                // mutably.
274                // the transition is only triggered when it emits a None
275                // item
276                // (we cannot do this at the place the `State` is constructed,
277                // because we don't yet know all its fields then; it must be
278                // done here.)
279                advance_match_arms.extend(quote! {
280                    Self::#name { #destructure } => {
281                        let mut #uses_mut = #uses_mut;
282                        match #advance_body {
283                            ::core::option::Option::Some(item) => {
284                                ::core::result::Result::Ok((::core::option::Option::Some(Self::#name { #destructure }), ::core::option::Option::Some(item)))
285                            },
286                            item => { #footer },
287                        }
288                    }
289                });
290            } else {
291                // if the variant is consuming, it can only be called once.
292                // it may or may not emit an event, but the transition is
293                // always triggered
294                advance_match_arms.extend(quote! {
295                    Self::#name { #destructure } => {
296                        let item = #advance_body;
297                        #footer
298                    }
299                });
300            }
301        }
302
303        AsItemsStateMachine {
304            defs: self.defs,
305            state_defs,
306            advance_match_arms,
307            variants: vec![AsItemsEntryPoint {
308                init: self.init,
309                destructure: self.destructure,
310            }],
311        }
312    }
313
314    /// Update the [`init`][`Self::init`] field in-place.
315    ///
316    /// The function will receive a reference to the current `init` value,
317    /// allowing to create "wrappers" around that existing code.
318    pub(crate) fn with_augmented_init<F: FnOnce(&TokenStream) -> TokenStream>(
319        mut self,
320        f: F,
321    ) -> Self {
322        let new_init = f(&self.init);
323        self.init = new_init;
324        self
325    }
326}
327
328/// Container for a single entrypoint into a [`FromEventsStateMachine`].
329pub(crate) struct FromEventsEntryPoint {
330    pub(crate) init: TokenStream,
331}
332
333/// A single variant's entrypoint into the event iterator.
334pub(crate) struct AsItemsEntryPoint {
335    /// A pattern match which destructures the target type into its parts, for
336    /// use by `init`.
337    destructure: TokenStream,
338
339    /// An expression which uses the names bound in `destructure` to create a
340    /// an instance of the state enum.
341    ///
342    /// The state enum type is available as `Self` in that context.
343    init: TokenStream,
344}
345
346/// # State machine to implement `xso::FromEventsBuilder`
347///
348/// This struct represents a state machine consisting of the following parts:
349///
350/// - Extra dependencies ([`Self::defs`])
351/// - States ([`Self::state_defs`])
352/// - Transitions ([`Self::advance_match_arms`])
353/// - Entrypoints ([`Self::variants`])
354///
355/// Such a state machine is best constructed by constructing one or
356/// more [`FromEventsSubmachine`] structs and converting/merging them using
357/// `into()` and [`merge`][`Self::merge`].
358///
359/// A state machine has an output type (corresponding to
360/// `xso::FromEventsBuilder::Output`), which is however only implicitly defined
361/// by the expressions generated in the `advance_match_arms`. That means that
362/// merging submachines with different output types works, but will then generate
363/// code which will fail to compile.
364///
365/// When converted to Rust code, the state machine will manifest as (among other
366/// things) an enum type which contains all states and which has an `advance`
367/// method. That method consumes the enum value and returns either a new enum
368/// value, an error, or the output type of the state machine.
369#[derive(Default)]
370pub(crate) struct FromEventsStateMachine {
371    /// Extra items which are needed for the state machine implementation.
372    defs: TokenStream,
373
374    /// Extra code run during pre-init phase.
375    pre_init: TokenStream,
376
377    /// Code to run as fallback if none of the branches matched the start
378    /// event.
379    ///
380    /// If absent, a `FromEventsError::Mismatch` is generated.
381    fallback: Option<TokenStream>,
382
383    /// A sequence of enum variant declarations, separated and terminated by
384    /// commas.
385    state_defs: TokenStream,
386
387    /// A sequence of `match self { .. }` arms, where `self` is the state
388    /// enumeration type.
389    ///
390    /// Each match arm must either diverge or evaluate to a
391    /// `Result<ControlFlow<State, Output>, xso::error::Error>`, where `State`
392    /// is the state enumeration and `Output` is the state machine's output
393    /// type.
394    advance_match_arms: TokenStream,
395
396    /// The different entrypoints for the state machine.
397    ///
398    /// This may only contain more than one element if an enumeration is being
399    /// constructed by the resulting state machine.
400    variants: Vec<FromEventsEntryPoint>,
401}
402
403impl FromEventsStateMachine {
404    /// Create a new, empty state machine.
405    pub(crate) fn new() -> Self {
406        Self {
407            defs: TokenStream::default(),
408            state_defs: TokenStream::default(),
409            advance_match_arms: TokenStream::default(),
410            pre_init: TokenStream::default(),
411            variants: Vec::new(),
412            fallback: None,
413        }
414    }
415
416    /// Merge another state machine into this state machine.
417    ///
418    /// This *discards* the other state machine's pre-init code.
419    pub(crate) fn merge(&mut self, other: FromEventsStateMachine) {
420        assert!(other.fallback.is_none());
421        self.defs.extend(other.defs);
422        self.state_defs.extend(other.state_defs);
423        self.advance_match_arms.extend(other.advance_match_arms);
424        self.variants.extend(other.variants);
425    }
426
427    /// Set additional code to inject at the head of the `new` method for the
428    /// builder.
429    ///
430    /// This can be used to do preliminary checks and is commonly used with
431    /// specifically-formed init codes on the variants.
432    pub(crate) fn set_pre_init(&mut self, code: TokenStream) {
433        self.pre_init = code;
434    }
435
436    /// Set the fallback code to use if none of the branches matches the start
437    /// event.
438    ///
439    /// By default, a `FromEventsError::Mismatch` is generated.
440    pub(crate) fn set_fallback(&mut self, code: TokenStream) {
441        self.fallback = Some(code);
442    }
443
444    /// Render the state machine as a token stream.
445    ///
446    /// The token stream contains the following pieces:
447    /// - Any definitions necessary for the statemachine to operate
448    /// - The state enum
449    /// - The builder struct
450    /// - The `xso::FromEventsBuilder` impl on the builder struct
451    /// - A `fn new(rxml::QName, rxml::AttrMap) -> Result<Self>` on the
452    ///   builder struct.
453    pub(crate) fn render(
454        self,
455        vis: &Visibility,
456        builder_ty_ident: &Ident,
457        state_ty_ident: &Ident,
458        output_ty: &Type,
459    ) -> Result<TokenStream> {
460        let Self {
461            defs,
462            state_defs,
463            advance_match_arms,
464            variants,
465            pre_init,
466            fallback,
467        } = self;
468
469        let mut init_body = pre_init;
470        for variant in variants {
471            let FromEventsEntryPoint { init } = variant;
472            init_body.extend(quote! {
473                let (name, mut attrs) = match { { let _ = &mut attrs; } #init } {
474                    ::core::result::Result::Ok(v) => return ::core::result::Result::Ok(v),
475                    ::core::result::Result::Err(::xso::error::FromEventsError::Invalid(e)) => return ::core::result::Result::Err(::xso::error::FromEventsError::Invalid(e)),
476                    ::core::result::Result::Err(::xso::error::FromEventsError::Mismatch { name, attrs }) => (name, attrs),
477                };
478            })
479        }
480
481        let fallback = fallback.unwrap_or_else(|| {
482            quote! {
483                ::core::result::Result::Err(::xso::error::FromEventsError::Mismatch { name, attrs })
484            }
485        });
486
487        let output_ty_ref = make_ty_ref(output_ty);
488
489        let docstr = format!("Build a {0} from XML events.\n\nThis type is generated using the [`macro@xso::FromXml`] derive macro and implements [`xso::FromEventsBuilder`] for {0}.", output_ty_ref);
490
491        Ok(quote! {
492            #defs
493
494            enum #state_ty_ident {
495                #state_defs
496            }
497
498            impl #state_ty_ident {
499                fn advance(mut self, ev: ::xso::exports::rxml::Event) -> ::core::result::Result<::core::ops::ControlFlow<Self, #output_ty>, ::xso::error::Error> {
500                    match self {
501                        #advance_match_arms
502                    }.and_then(|__ok| {
503                        match __ok {
504                            ::core::ops::ControlFlow::Break(st) => ::core::result::Result::Ok(::core::ops::ControlFlow::Break(st)),
505                            ::core::ops::ControlFlow::Continue(result) => {
506                                ::core::result::Result::Ok(::core::ops::ControlFlow::Continue(result))
507                            }
508                        }
509                    })
510                }
511            }
512
513            impl #builder_ty_ident {
514                fn new(
515                    name: ::xso::exports::rxml::QName,
516                    attrs: ::xso::exports::rxml::AttrMap,
517                ) -> ::core::result::Result<Self, ::xso::error::FromEventsError> {
518                    #state_ty_ident::new(name, attrs).map(|ok| Self(::core::option::Option::Some(ok)))
519                }
520            }
521
522            #[doc = #docstr]
523            #[doc(hidden)]
524            #vis struct #builder_ty_ident(::core::option::Option<#state_ty_ident>);
525
526            impl ::xso::FromEventsBuilder for #builder_ty_ident {
527                type Output = #output_ty;
528
529                fn feed(&mut self, ev: ::xso::exports::rxml::Event) -> ::core::result::Result<::core::option::Option<Self::Output>, ::xso::error::Error> {
530                    let inner = self.0.take().expect("feed called after completion");
531                    match inner.advance(ev)? {
532                        ::core::ops::ControlFlow::Continue(value) => ::core::result::Result::Ok(::core::option::Option::Some(value)),
533                        ::core::ops::ControlFlow::Break(st) => {
534                            self.0 = ::core::option::Option::Some(st);
535                            ::core::result::Result::Ok(::core::option::Option::None)
536                        }
537                    }
538                }
539            }
540
541            impl #state_ty_ident {
542                fn new(
543                    name: ::xso::exports::rxml::QName,
544                    mut attrs: ::xso::exports::rxml::AttrMap,
545                ) -> ::core::result::Result<Self, ::xso::error::FromEventsError> {
546                    #init_body
547                    { let _ = &mut attrs; }
548                    #fallback
549                }
550            }
551        })
552    }
553}
554
555/// # State machine to implement an `Iterator<Item = rxml::Event>`.
556///
557/// This struct represents a state machine consisting of the following parts:
558///
559/// - Extra dependencies ([`Self::defs`])
560/// - States ([`Self::state_defs`])
561/// - Transitions ([`Self::advance_match_arms`])
562/// - Entrypoints ([`Self::variants`])
563///
564/// Such a state machine is best constructed by constructing one or
565/// more [`FromEventsSubmachine`] structs and converting/merging them using
566/// `into()` and [`merge`][`Self::merge`].
567///
568/// A state machine has an output type (corresponding to
569/// `xso::FromEventsBuilder::Output`), which is however only implicitly defined
570/// by the expressions generated in the `advance_match_arms`. That means that
571/// merging submachines with different output types works, but will then generate
572/// code which will fail to compile.
573///
574/// When converted to Rust code, the state machine will manifest as (among other
575/// things) an enum type which contains all states and which has an `advance`
576/// method. That method consumes the enum value and returns either a new enum
577/// value, an error, or the output type of the state machine.
578#[derive(Default)]
579pub(crate) struct AsItemsStateMachine {
580    /// Extra items which are needed for the state machine implementation.
581    defs: TokenStream,
582
583    /// A sequence of enum variant declarations, separated and terminated by
584    /// commas.
585    state_defs: TokenStream,
586
587    /// A sequence of `match self { .. }` arms, where `self` is the state
588    /// enumeration type.
589    ///
590    /// Each match arm must either diverge or evaluate to a
591    /// `Result<(Option<State>, Option<Item>), xso::error::Error>`, where
592    /// where `State` is the state enumeration.
593    ///
594    /// If `Some(.)` is returned for the event, that event is emitted. If
595    /// `None` is returned for the event, the advance implementation is called
596    /// again after switching to the state returned in the `Option<State>`
597    /// field.
598    ///
599    /// If `None` is returned for the `Option<State>`, the iterator
600    /// terminates yielding the `Option<Item>` value directly (even if it is
601    /// `None`). After the iterator has terminated, it yields `None`
602    /// indefinitely.
603    advance_match_arms: TokenStream,
604
605    /// The different entrypoints for the state machine.
606    ///
607    /// This may only contain more than one element if an enumeration is being
608    /// serialised by the resulting state machine.
609    variants: Vec<AsItemsEntryPoint>,
610}
611
612impl AsItemsStateMachine {
613    /// Create a new, empty state machine.
614    pub(crate) fn new() -> Self {
615        Self {
616            defs: TokenStream::default(),
617            state_defs: TokenStream::default(),
618            advance_match_arms: TokenStream::default(),
619            variants: Vec::new(),
620        }
621    }
622
623    /// Merge another state machine into this state machine.
624    pub(crate) fn merge(&mut self, other: AsItemsStateMachine) {
625        self.defs.extend(other.defs);
626        self.state_defs.extend(other.state_defs);
627        self.advance_match_arms.extend(other.advance_match_arms);
628        self.variants.extend(other.variants);
629    }
630
631    /// Render the state machine as a token stream.
632    ///
633    /// The token stream contains the following pieces:
634    /// - Any definitions necessary for the statemachine to operate
635    /// - The state enum
636    /// - The iterator struct
637    /// - The `Iterator` impl on the builder struct
638    /// - A `fn new(T) -> Result<Self>` on the iterator struct.
639    pub(crate) fn render(
640        self,
641        vis: &Visibility,
642        input_ty_ref: &Type,
643        state_ty_ident: &Ident,
644        item_iter_ty_lifetime: &Lifetime,
645        item_iter_ty: &Type,
646    ) -> Result<TokenStream> {
647        let Self {
648            defs,
649            state_defs,
650            advance_match_arms,
651            mut variants,
652        } = self;
653
654        let input_ty_ref_text = make_ty_ref(input_ty_ref);
655        let docstr = format!("Convert a {0} into XML events.\n\nThis type is generated using the [`macro@xso::AsXml`] derive macro and implements [`core::iter:Iterator`] for {0}.", input_ty_ref_text);
656
657        let init_body = if variants.len() == 1 {
658            let AsItemsEntryPoint { destructure, init } = variants.remove(0);
659            quote! {
660                {
661                    let #destructure = value;
662                    #init
663                }
664            }
665        } else {
666            let mut match_arms = TokenStream::default();
667            for AsItemsEntryPoint { destructure, init } in variants {
668                match_arms.extend(quote! {
669                    #destructure => { #init }
670                });
671            }
672
673            quote! {
674                match value {
675                    #match_arms
676                }
677            }
678        };
679
680        Ok(quote! {
681            #defs
682
683            enum #state_ty_ident<#item_iter_ty_lifetime> {
684                #state_defs
685            }
686
687            impl<#item_iter_ty_lifetime> #state_ty_ident<#item_iter_ty_lifetime> {
688                fn advance(mut self) -> ::core::result::Result<(::core::option::Option<Self>, ::core::option::Option<::xso::Item<#item_iter_ty_lifetime>>), ::xso::error::Error> {
689                    match self {
690                        #advance_match_arms
691                    }
692                }
693
694                fn new(
695                    value: #input_ty_ref,
696                ) -> ::core::result::Result<Self, ::xso::error::Error> {
697                    ::core::result::Result::Ok(#init_body)
698                }
699            }
700
701            #[doc = #docstr]
702            #[doc(hidden)]
703            #vis struct #item_iter_ty(::core::option::Option<#state_ty_ident<#item_iter_ty_lifetime>>);
704
705            impl<#item_iter_ty_lifetime> ::core::iter::Iterator for #item_iter_ty {
706                type Item = ::core::result::Result<::xso::Item<#item_iter_ty_lifetime>, ::xso::error::Error>;
707
708                fn next(&mut self) -> ::core::option::Option<Self::Item> {
709                    let mut state = self.0.take()?;
710                    loop {
711                        let (next_state, item) = match state.advance() {
712                            ::core::result::Result::Ok(v) => v,
713                            ::core::result::Result::Err(e) => return ::core::option::Option::Some(::core::result::Result::Err(e)),
714                        };
715                        if let ::core::option::Option::Some(item) = item {
716                            self.0 = next_state;
717                            return ::core::option::Option::Some(::core::result::Result::Ok(item));
718                        }
719                        // no event, do we have a state?
720                        if let ::core::option::Option::Some(st) = next_state {
721                            // we do: try again!
722                            state = st;
723                            continue;
724                        } else {
725                            // we don't: end of iterator!
726                            self.0 = ::core::option::Option::None;
727                            return ::core::option::Option::None;
728                        }
729                    }
730                }
731            }
732
733            impl<#item_iter_ty_lifetime> #item_iter_ty {
734                fn new(value: #input_ty_ref) -> ::core::result::Result<Self, ::xso::error::Error> {
735                    #state_ty_ident::new(value).map(|ok| Self(::core::option::Option::Some(ok)))
736                }
737            }
738        })
739    }
740}
741
742/// Construct a path for an intradoc link from a given type.
743fn doc_link_path(ty: &Type) -> Option<String> {
744    match ty {
745        Type::Path(ref ty) => {
746            let (mut buf, offset) = match ty.qself {
747                Some(ref qself) => {
748                    let mut buf = doc_link_path(&qself.ty)?;
749                    buf.push_str("::");
750                    (buf, qself.position)
751                }
752                None => {
753                    let mut buf = String::new();
754                    if ty.path.leading_colon.is_some() {
755                        buf.push_str("::");
756                    }
757                    (buf, 0)
758                }
759            };
760            let last = ty.path.segments.len() - 1;
761            for i in offset..ty.path.segments.len() {
762                let segment = &ty.path.segments[i];
763                buf.push_str(&segment.ident.to_string());
764                if i < last {
765                    buf.push_str("::");
766                }
767            }
768            Some(buf)
769        }
770        Type::Reference(TypeReference { ref elem, .. }) => doc_link_path(elem),
771        _ => None,
772    }
773}
774
775/// Create a markdown snippet which references the given type as cleanly as
776/// possible.
777///
778/// This is used in documentation generation functions.
779///
780/// Not all types can be linked to; those which cannot be linked to will
781/// simply be wrapped in backticks.
782fn make_ty_ref(ty: &Type) -> String {
783    match doc_link_path(ty) {
784        Some(mut path) => {
785            path.reserve(4);
786            path.insert_str(0, "[`");
787            path.push_str("`]");
788            path
789        }
790        None => format!("`{}`", ty.to_token_stream()),
791    }
792}