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            #vis struct #builder_ty_ident(::core::option::Option<#state_ty_ident>);
524
525            impl ::xso::FromEventsBuilder for #builder_ty_ident {
526                type Output = #output_ty;
527
528                fn feed(&mut self, ev: ::xso::exports::rxml::Event) -> ::core::result::Result<::core::option::Option<Self::Output>, ::xso::error::Error> {
529                    let inner = self.0.take().expect("feed called after completion");
530                    match inner.advance(ev)? {
531                        ::core::ops::ControlFlow::Continue(value) => ::core::result::Result::Ok(::core::option::Option::Some(value)),
532                        ::core::ops::ControlFlow::Break(st) => {
533                            self.0 = ::core::option::Option::Some(st);
534                            ::core::result::Result::Ok(::core::option::Option::None)
535                        }
536                    }
537                }
538            }
539
540            impl #state_ty_ident {
541                fn new(
542                    name: ::xso::exports::rxml::QName,
543                    mut attrs: ::xso::exports::rxml::AttrMap,
544                ) -> ::core::result::Result<Self, ::xso::error::FromEventsError> {
545                    #init_body
546                    { let _ = &mut attrs; }
547                    #fallback
548                }
549            }
550        })
551    }
552}
553
554/// # State machine to implement an `Iterator<Item = rxml::Event>`.
555///
556/// This struct represents a state machine consisting of the following parts:
557///
558/// - Extra dependencies ([`Self::defs`])
559/// - States ([`Self::state_defs`])
560/// - Transitions ([`Self::advance_match_arms`])
561/// - Entrypoints ([`Self::variants`])
562///
563/// Such a state machine is best constructed by constructing one or
564/// more [`FromEventsSubmachine`] structs and converting/merging them using
565/// `into()` and [`merge`][`Self::merge`].
566///
567/// A state machine has an output type (corresponding to
568/// `xso::FromEventsBuilder::Output`), which is however only implicitly defined
569/// by the expressions generated in the `advance_match_arms`. That means that
570/// merging submachines with different output types works, but will then generate
571/// code which will fail to compile.
572///
573/// When converted to Rust code, the state machine will manifest as (among other
574/// things) an enum type which contains all states and which has an `advance`
575/// method. That method consumes the enum value and returns either a new enum
576/// value, an error, or the output type of the state machine.
577#[derive(Default)]
578pub(crate) struct AsItemsStateMachine {
579    /// Extra items which are needed for the state machine implementation.
580    defs: TokenStream,
581
582    /// A sequence of enum variant declarations, separated and terminated by
583    /// commas.
584    state_defs: TokenStream,
585
586    /// A sequence of `match self { .. }` arms, where `self` is the state
587    /// enumeration type.
588    ///
589    /// Each match arm must either diverge or evaluate to a
590    /// `Result<(Option<State>, Option<Item>), xso::error::Error>`, where
591    /// where `State` is the state enumeration.
592    ///
593    /// If `Some(.)` is returned for the event, that event is emitted. If
594    /// `None` is returned for the event, the advance implementation is called
595    /// again after switching to the state returned in the `Option<State>`
596    /// field.
597    ///
598    /// If `None` is returned for the `Option<State>`, the iterator
599    /// terminates yielding the `Option<Item>` value directly (even if it is
600    /// `None`). After the iterator has terminated, it yields `None`
601    /// indefinitely.
602    advance_match_arms: TokenStream,
603
604    /// The different entrypoints for the state machine.
605    ///
606    /// This may only contain more than one element if an enumeration is being
607    /// serialised by the resulting state machine.
608    variants: Vec<AsItemsEntryPoint>,
609}
610
611impl AsItemsStateMachine {
612    /// Create a new, empty state machine.
613    pub(crate) fn new() -> Self {
614        Self {
615            defs: TokenStream::default(),
616            state_defs: TokenStream::default(),
617            advance_match_arms: TokenStream::default(),
618            variants: Vec::new(),
619        }
620    }
621
622    /// Merge another state machine into this state machine.
623    pub(crate) fn merge(&mut self, other: AsItemsStateMachine) {
624        self.defs.extend(other.defs);
625        self.state_defs.extend(other.state_defs);
626        self.advance_match_arms.extend(other.advance_match_arms);
627        self.variants.extend(other.variants);
628    }
629
630    /// Render the state machine as a token stream.
631    ///
632    /// The token stream contains the following pieces:
633    /// - Any definitions necessary for the statemachine to operate
634    /// - The state enum
635    /// - The iterator struct
636    /// - The `Iterator` impl on the builder struct
637    /// - A `fn new(T) -> Result<Self>` on the iterator struct.
638    pub(crate) fn render(
639        self,
640        vis: &Visibility,
641        input_ty_ref: &Type,
642        state_ty_ident: &Ident,
643        item_iter_ty_lifetime: &Lifetime,
644        item_iter_ty: &Type,
645    ) -> Result<TokenStream> {
646        let Self {
647            defs,
648            state_defs,
649            advance_match_arms,
650            mut variants,
651        } = self;
652
653        let input_ty_ref_text = make_ty_ref(input_ty_ref);
654        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);
655
656        let init_body = if variants.len() == 1 {
657            let AsItemsEntryPoint { destructure, init } = variants.remove(0);
658            quote! {
659                {
660                    let #destructure = value;
661                    #init
662                }
663            }
664        } else {
665            let mut match_arms = TokenStream::default();
666            for AsItemsEntryPoint { destructure, init } in variants {
667                match_arms.extend(quote! {
668                    #destructure => { #init }
669                });
670            }
671
672            quote! {
673                match value {
674                    #match_arms
675                }
676            }
677        };
678
679        Ok(quote! {
680            #defs
681
682            enum #state_ty_ident<#item_iter_ty_lifetime> {
683                #state_defs
684            }
685
686            impl<#item_iter_ty_lifetime> #state_ty_ident<#item_iter_ty_lifetime> {
687                fn advance(mut self) -> ::core::result::Result<(::core::option::Option<Self>, ::core::option::Option<::xso::Item<#item_iter_ty_lifetime>>), ::xso::error::Error> {
688                    match self {
689                        #advance_match_arms
690                    }
691                }
692
693                fn new(
694                    value: #input_ty_ref,
695                ) -> ::core::result::Result<Self, ::xso::error::Error> {
696                    ::core::result::Result::Ok(#init_body)
697                }
698            }
699
700            #[doc = #docstr]
701            #vis struct #item_iter_ty(::core::option::Option<#state_ty_ident<#item_iter_ty_lifetime>>);
702
703            impl<#item_iter_ty_lifetime> ::core::iter::Iterator for #item_iter_ty {
704                type Item = ::core::result::Result<::xso::Item<#item_iter_ty_lifetime>, ::xso::error::Error>;
705
706                fn next(&mut self) -> ::core::option::Option<Self::Item> {
707                    let mut state = self.0.take()?;
708                    loop {
709                        let (next_state, item) = match state.advance() {
710                            ::core::result::Result::Ok(v) => v,
711                            ::core::result::Result::Err(e) => return ::core::option::Option::Some(::core::result::Result::Err(e)),
712                        };
713                        if let ::core::option::Option::Some(item) = item {
714                            self.0 = next_state;
715                            return ::core::option::Option::Some(::core::result::Result::Ok(item));
716                        }
717                        // no event, do we have a state?
718                        if let ::core::option::Option::Some(st) = next_state {
719                            // we do: try again!
720                            state = st;
721                            continue;
722                        } else {
723                            // we don't: end of iterator!
724                            self.0 = ::core::option::Option::None;
725                            return ::core::option::Option::None;
726                        }
727                    }
728                }
729            }
730
731            impl<#item_iter_ty_lifetime> #item_iter_ty {
732                fn new(value: #input_ty_ref) -> ::core::result::Result<Self, ::xso::error::Error> {
733                    #state_ty_ident::new(value).map(|ok| Self(::core::option::Option::Some(ok)))
734                }
735            }
736        })
737    }
738}
739
740/// Construct a path for an intradoc link from a given type.
741fn doc_link_path(ty: &Type) -> Option<String> {
742    match ty {
743        Type::Path(ref ty) => {
744            let (mut buf, offset) = match ty.qself {
745                Some(ref qself) => {
746                    let mut buf = doc_link_path(&qself.ty)?;
747                    buf.push_str("::");
748                    (buf, qself.position)
749                }
750                None => {
751                    let mut buf = String::new();
752                    if ty.path.leading_colon.is_some() {
753                        buf.push_str("::");
754                    }
755                    (buf, 0)
756                }
757            };
758            let last = ty.path.segments.len() - 1;
759            for i in offset..ty.path.segments.len() {
760                let segment = &ty.path.segments[i];
761                buf.push_str(&segment.ident.to_string());
762                if i < last {
763                    buf.push_str("::");
764                }
765            }
766            Some(buf)
767        }
768        Type::Reference(TypeReference { ref elem, .. }) => doc_link_path(elem),
769        _ => None,
770    }
771}
772
773/// Create a markdown snippet which references the given type as cleanly as
774/// possible.
775///
776/// This is used in documentation generation functions.
777///
778/// Not all types can be linked to; those which cannot be linked to will
779/// simply be wrapped in backticks.
780fn make_ty_ref(ty: &Type) -> String {
781    match doc_link_path(ty) {
782        Some(mut path) => {
783            path.reserve(4);
784            path.insert_str(0, "[`");
785            path.push_str("`]");
786            path
787        }
788        None => format!("`{}`", ty.to_token_stream()),
789    }
790}