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        }
181    }
182
183    /// Update the [`init`][`Self::init`] field in-place.
184    ///
185    /// The function will receive a reference to the current `init` value,
186    /// allowing to create "wrappers" around that existing code.
187    pub(crate) fn with_augmented_init<F: FnOnce(&TokenStream) -> TokenStream>(
188        mut self,
189        f: F,
190    ) -> Self {
191        let new_init = f(&self.init);
192        self.init = new_init;
193        self
194    }
195}
196
197/// A partial [`AsItemsStateMachine`] which only covers the builder for a
198/// single compound.
199///
200/// See [`AsItemsStateMachine`] for more information on the state machines
201/// in general.
202pub(crate) struct AsItemsSubmachine {
203    /// Additional items necessary for the statemachine.
204    pub(crate) defs: TokenStream,
205
206    /// States and state transition implementations.
207    pub(crate) states: Vec<State>,
208
209    /// A pattern match which destructures the target type into its parts, for
210    /// use by `init`.
211    pub(crate) destructure: TokenStream,
212
213    /// An expression which uses the names bound in `destructure` to create a
214    /// an instance of the state enum.
215    ///
216    /// The state enum type is available as `Self` in that context.
217    pub(crate) init: TokenStream,
218}
219
220impl AsItemsSubmachine {
221    /// Convert a partial state machine into a full state machine.
222    ///
223    /// This converts the abstract [`State`] items into token
224    /// streams for the respective parts of the state machine (the state
225    /// definitions and the match arms), rendering them effectively immutable.
226    ///
227    /// This requires that the [`State::advance_body`] token streams evaluate
228    /// to an `Option<Item>`. If it evaluates to `Some(.)`, that is
229    /// emitted from the iterator. If it evaluates to `None`, the `advance`
230    /// implementation is called again.
231    ///
232    /// Each state implementation is augmented to also enter the next state,
233    /// causing the iterator to terminate eventually.
234    pub(crate) fn compile(self) -> AsItemsStateMachine {
235        let mut state_defs = TokenStream::default();
236        let mut advance_match_arms = TokenStream::default();
237
238        for (i, state) in self.states.iter().enumerate() {
239            let State {
240                ref name,
241                ref decl,
242                ref destructure,
243                ref advance_body,
244                ref uses_mut,
245            } = state;
246
247            let footer = match self.states.get(i + 1) {
248                Some(State {
249                    name: ref next_name,
250                    destructure: ref construct_next,
251                    ..
252                }) => {
253                    quote! {
254                        ::core::result::Result::Ok((::core::option::Option::Some(Self::#next_name { #construct_next }), item))
255                    }
256                }
257                // final state -> exit the state machine
258                None => {
259                    quote! {
260                        ::core::result::Result::Ok((::core::option::Option::None, item))
261                    }
262                }
263            };
264
265            state_defs.extend(quote! {
266                #name { #decl },
267            });
268
269            if let Some(uses_mut) = uses_mut.as_ref() {
270                // the variant is non-consuming, meaning it can be called
271                // multiple times and it uses the identifier in `uses_mut`
272                // mutably.
273                // the transition is only triggered when it emits a None
274                // item
275                // (we cannot do this at the place the `State` is constructed,
276                // because we don't yet know all its fields then; it must be
277                // done here.)
278                advance_match_arms.extend(quote! {
279                    Self::#name { #destructure } => {
280                        let mut #uses_mut = #uses_mut;
281                        match #advance_body {
282                            ::std::option::Option::Some(item) => {
283                                ::std::result::Result::Ok((::std::option::Option::Some(Self::#name { #destructure }), ::std::option::Option::Some(item)))
284                            },
285                            item => { #footer },
286                        }
287                    }
288                });
289            } else {
290                // if the variant is consuming, it can only be called once.
291                // it may or may not emit an event, but the transition is
292                // always triggered
293                advance_match_arms.extend(quote! {
294                    Self::#name { #destructure } => {
295                        let item = #advance_body;
296                        #footer
297                    }
298                });
299            }
300        }
301
302        AsItemsStateMachine {
303            defs: self.defs,
304            state_defs,
305            advance_match_arms,
306            variants: vec![AsItemsEntryPoint {
307                init: self.init,
308                destructure: self.destructure,
309            }],
310        }
311    }
312
313    /// Update the [`init`][`Self::init`] field in-place.
314    ///
315    /// The function will receive a reference to the current `init` value,
316    /// allowing to create "wrappers" around that existing code.
317    pub(crate) fn with_augmented_init<F: FnOnce(&TokenStream) -> TokenStream>(
318        mut self,
319        f: F,
320    ) -> Self {
321        let new_init = f(&self.init);
322        self.init = new_init;
323        self
324    }
325}
326
327/// Container for a single entrypoint into a [`FromEventsStateMachine`].
328pub(crate) struct FromEventsEntryPoint {
329    pub(crate) init: TokenStream,
330}
331
332/// A single variant's entrypoint into the event iterator.
333pub(crate) struct AsItemsEntryPoint {
334    /// A pattern match which destructures the target type into its parts, for
335    /// use by `init`.
336    destructure: TokenStream,
337
338    /// An expression which uses the names bound in `destructure` to create a
339    /// an instance of the state enum.
340    ///
341    /// The state enum type is available as `Self` in that context.
342    init: TokenStream,
343}
344
345/// # State machine to implement `xso::FromEventsBuilder`
346///
347/// This struct represents a state machine consisting of the following parts:
348///
349/// - Extra dependencies ([`Self::defs`])
350/// - States ([`Self::state_defs`])
351/// - Transitions ([`Self::advance_match_arms`])
352/// - Entrypoints ([`Self::variants`])
353///
354/// Such a state machine is best constructed by constructing one or
355/// more [`FromEventsSubmachine`] structs and converting/merging them using
356/// `into()` and [`merge`][`Self::merge`].
357///
358/// A state machine has an output type (corresponding to
359/// `xso::FromEventsBuilder::Output`), which is however only implicitly defined
360/// by the expressions generated in the `advance_match_arms`. That means that
361/// merging submachines with different output types works, but will then generate
362/// code which will fail to compile.
363///
364/// When converted to Rust code, the state machine will manifest as (among other
365/// things) an enum type which contains all states and which has an `advance`
366/// method. That method consumes the enum value and returns either a new enum
367/// value, an error, or the output type of the state machine.
368#[derive(Default)]
369pub(crate) struct FromEventsStateMachine {
370    /// Extra items which are needed for the state machine implementation.
371    defs: TokenStream,
372
373    /// Extra code run during pre-init phase.
374    pre_init: TokenStream,
375
376    /// A sequence of enum variant declarations, separated and terminated by
377    /// commas.
378    state_defs: TokenStream,
379
380    /// A sequence of `match self { .. }` arms, where `self` is the state
381    /// enumeration type.
382    ///
383    /// Each match arm must either diverge or evaluate to a
384    /// `Result<ControlFlow<State, Output>, xso::error::Error>`, where `State`
385    /// is the state enumeration and `Output` is the state machine's output
386    /// type.
387    advance_match_arms: TokenStream,
388
389    /// The different entrypoints for the state machine.
390    ///
391    /// This may only contain more than one element if an enumeration is being
392    /// constructed by the resulting state machine.
393    variants: Vec<FromEventsEntryPoint>,
394}
395
396impl FromEventsStateMachine {
397    /// Create a new, empty state machine.
398    pub(crate) fn new() -> Self {
399        Self {
400            defs: TokenStream::default(),
401            state_defs: TokenStream::default(),
402            advance_match_arms: TokenStream::default(),
403            pre_init: TokenStream::default(),
404            variants: Vec::new(),
405        }
406    }
407
408    /// Merge another state machine into this state machine.
409    ///
410    /// This *discards* the other state machine's pre-init code.
411    pub(crate) fn merge(&mut self, other: FromEventsStateMachine) {
412        self.defs.extend(other.defs);
413        self.state_defs.extend(other.state_defs);
414        self.advance_match_arms.extend(other.advance_match_arms);
415        self.variants.extend(other.variants);
416    }
417
418    /// Set additional code to inject at the head of the `new` method for the
419    /// builder.
420    ///
421    /// This can be used to do preliminary checks and is commonly used with
422    /// specifically-formed init codes on the variants.
423    pub(crate) fn set_pre_init(&mut self, code: TokenStream) {
424        self.pre_init = code;
425    }
426
427    /// Render the state machine as a token stream.
428    ///
429    /// The token stream contains the following pieces:
430    /// - Any definitions necessary for the statemachine to operate
431    /// - The state enum
432    /// - The builder struct
433    /// - The `xso::FromEventsBuilder` impl on the builder struct
434    /// - A `fn new(rxml::QName, rxml::AttrMap) -> Result<Self>` on the
435    ///   builder struct.
436    pub(crate) fn render(
437        self,
438        vis: &Visibility,
439        builder_ty_ident: &Ident,
440        state_ty_ident: &Ident,
441        output_ty: &Type,
442    ) -> Result<TokenStream> {
443        let Self {
444            defs,
445            state_defs,
446            advance_match_arms,
447            variants,
448            pre_init,
449        } = self;
450
451        let mut init_body = pre_init;
452        for variant in variants {
453            let FromEventsEntryPoint { init } = variant;
454            init_body.extend(quote! {
455                let (name, mut attrs) = match { { let _ = &mut attrs; } #init } {
456                    ::core::result::Result::Ok(v) => return ::core::result::Result::Ok(v),
457                    ::core::result::Result::Err(::xso::error::FromEventsError::Invalid(e)) => return ::core::result::Result::Err(::xso::error::FromEventsError::Invalid(e)),
458                    ::core::result::Result::Err(::xso::error::FromEventsError::Mismatch { name, attrs }) => (name, attrs),
459                };
460            })
461        }
462
463        let output_ty_ref = make_ty_ref(output_ty);
464
465        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);
466
467        Ok(quote! {
468            #defs
469
470            enum #state_ty_ident {
471                #state_defs
472            }
473
474            impl #state_ty_ident {
475                fn advance(mut self, ev: ::xso::exports::rxml::Event) -> ::core::result::Result<::std::ops::ControlFlow<Self, #output_ty>, ::xso::error::Error> {
476                    match self {
477                        #advance_match_arms
478                    }.and_then(|__ok| {
479                        match __ok {
480                            ::std::ops::ControlFlow::Break(st) => ::core::result::Result::Ok(::std::ops::ControlFlow::Break(st)),
481                            ::std::ops::ControlFlow::Continue(result) => {
482                                ::core::result::Result::Ok(::std::ops::ControlFlow::Continue(result))
483                            }
484                        }
485                    })
486                }
487            }
488
489            impl #builder_ty_ident {
490                fn new(
491                    name: ::xso::exports::rxml::QName,
492                    attrs: ::xso::exports::rxml::AttrMap,
493                ) -> ::core::result::Result<Self, ::xso::error::FromEventsError> {
494                    #state_ty_ident::new(name, attrs).map(|ok| Self(::core::option::Option::Some(ok)))
495                }
496            }
497
498            #[doc = #docstr]
499            #vis struct #builder_ty_ident(::core::option::Option<#state_ty_ident>);
500
501            impl ::xso::FromEventsBuilder for #builder_ty_ident {
502                type Output = #output_ty;
503
504                fn feed(&mut self, ev: ::xso::exports::rxml::Event) -> ::core::result::Result<::core::option::Option<Self::Output>, ::xso::error::Error> {
505                    let inner = self.0.take().expect("feed called after completion");
506                    match inner.advance(ev)? {
507                        ::std::ops::ControlFlow::Continue(value) => ::core::result::Result::Ok(::core::option::Option::Some(value)),
508                        ::std::ops::ControlFlow::Break(st) => {
509                            self.0 = ::core::option::Option::Some(st);
510                            ::core::result::Result::Ok(::core::option::Option::None)
511                        }
512                    }
513                }
514            }
515
516            impl #state_ty_ident {
517                fn new(
518                    name: ::xso::exports::rxml::QName,
519                    mut attrs: ::xso::exports::rxml::AttrMap,
520                ) -> ::core::result::Result<Self, ::xso::error::FromEventsError> {
521                    #init_body
522                    { let _ = &mut attrs; }
523                    ::core::result::Result::Err(::xso::error::FromEventsError::Mismatch { name, attrs })
524                }
525            }
526        })
527    }
528}
529
530/// # State machine to implement an `Iterator<Item = rxml::Event>`.
531///
532/// This struct represents a state machine consisting of the following parts:
533///
534/// - Extra dependencies ([`Self::defs`])
535/// - States ([`Self::state_defs`])
536/// - Transitions ([`Self::advance_match_arms`])
537/// - Entrypoints ([`Self::variants`])
538///
539/// Such a state machine is best constructed by constructing one or
540/// more [`FromEventsSubmachine`] structs and converting/merging them using
541/// `into()` and [`merge`][`Self::merge`].
542///
543/// A state machine has an output type (corresponding to
544/// `xso::FromEventsBuilder::Output`), which is however only implicitly defined
545/// by the expressions generated in the `advance_match_arms`. That means that
546/// merging submachines with different output types works, but will then generate
547/// code which will fail to compile.
548///
549/// When converted to Rust code, the state machine will manifest as (among other
550/// things) an enum type which contains all states and which has an `advance`
551/// method. That method consumes the enum value and returns either a new enum
552/// value, an error, or the output type of the state machine.
553#[derive(Default)]
554pub(crate) struct AsItemsStateMachine {
555    /// Extra items which are needed for the state machine implementation.
556    defs: TokenStream,
557
558    /// A sequence of enum variant declarations, separated and terminated by
559    /// commas.
560    state_defs: TokenStream,
561
562    /// A sequence of `match self { .. }` arms, where `self` is the state
563    /// enumeration type.
564    ///
565    /// Each match arm must either diverge or evaluate to a
566    /// `Result<(Option<State>, Option<Item>), xso::error::Error>`, where
567    /// where `State` is the state enumeration.
568    ///
569    /// If `Some(.)` is returned for the event, that event is emitted. If
570    /// `None` is returned for the event, the advance implementation is called
571    /// again after switching to the state returned in the `Option<State>`
572    /// field.
573    ///
574    /// If `None` is returned for the `Option<State>`, the iterator
575    /// terminates yielding the `Option<Item>` value directly (even if it is
576    /// `None`). After the iterator has terminated, it yields `None`
577    /// indefinitely.
578    advance_match_arms: TokenStream,
579
580    /// The different entrypoints for the state machine.
581    ///
582    /// This may only contain more than one element if an enumeration is being
583    /// serialised by the resulting state machine.
584    variants: Vec<AsItemsEntryPoint>,
585}
586
587impl AsItemsStateMachine {
588    /// Create a new, empty state machine.
589    pub(crate) fn new() -> Self {
590        Self {
591            defs: TokenStream::default(),
592            state_defs: TokenStream::default(),
593            advance_match_arms: TokenStream::default(),
594            variants: Vec::new(),
595        }
596    }
597
598    /// Merge another state machine into this state machine.
599    pub(crate) fn merge(&mut self, other: AsItemsStateMachine) {
600        self.defs.extend(other.defs);
601        self.state_defs.extend(other.state_defs);
602        self.advance_match_arms.extend(other.advance_match_arms);
603        self.variants.extend(other.variants);
604    }
605
606    /// Render the state machine as a token stream.
607    ///
608    /// The token stream contains the following pieces:
609    /// - Any definitions necessary for the statemachine to operate
610    /// - The state enum
611    /// - The iterator struct
612    /// - The `Iterator` impl on the builder struct
613    /// - A `fn new(T) -> Result<Self>` on the iterator struct.
614    pub(crate) fn render(
615        self,
616        vis: &Visibility,
617        input_ty: &Type,
618        state_ty_ident: &Ident,
619        item_iter_ty_lifetime: &Lifetime,
620        item_iter_ty: &Type,
621    ) -> Result<TokenStream> {
622        let Self {
623            defs,
624            state_defs,
625            advance_match_arms,
626            mut variants,
627        } = self;
628
629        let input_ty_ref = make_ty_ref(input_ty);
630        let docstr = format!("Convert a {0} into XML events.\n\nThis type is generated using the [`macro@xso::AsXml`] derive macro and implements [`std::iter:Iterator`] for {0}.", input_ty_ref);
631
632        let init_body = if variants.len() == 1 {
633            let AsItemsEntryPoint { destructure, init } = variants.remove(0);
634            quote! {
635                {
636                    let #destructure = value;
637                    #init
638                }
639            }
640        } else {
641            let mut match_arms = TokenStream::default();
642            for AsItemsEntryPoint { destructure, init } in variants {
643                match_arms.extend(quote! {
644                    #destructure => { #init }
645                });
646            }
647
648            quote! {
649                match value {
650                    #match_arms
651                }
652            }
653        };
654
655        Ok(quote! {
656            #defs
657
658            enum #state_ty_ident<#item_iter_ty_lifetime> {
659                #state_defs
660            }
661
662            impl<#item_iter_ty_lifetime> #state_ty_ident<#item_iter_ty_lifetime> {
663                fn advance(mut self) -> ::core::result::Result<(::core::option::Option<Self>, ::core::option::Option<::xso::Item<#item_iter_ty_lifetime>>), ::xso::error::Error> {
664                    match self {
665                        #advance_match_arms
666                    }
667                }
668
669                fn new(
670                    value: &#item_iter_ty_lifetime #input_ty,
671                ) -> ::core::result::Result<Self, ::xso::error::Error> {
672                    ::core::result::Result::Ok(#init_body)
673                }
674            }
675
676            #[doc = #docstr]
677            #vis struct #item_iter_ty(::core::option::Option<#state_ty_ident<#item_iter_ty_lifetime>>);
678
679            impl<#item_iter_ty_lifetime> ::std::iter::Iterator for #item_iter_ty {
680                type Item = ::core::result::Result<::xso::Item<#item_iter_ty_lifetime>, ::xso::error::Error>;
681
682                fn next(&mut self) -> ::core::option::Option<Self::Item> {
683                    let mut state = self.0.take()?;
684                    loop {
685                        let (next_state, item) = match state.advance() {
686                            ::core::result::Result::Ok(v) => v,
687                            ::core::result::Result::Err(e) => return ::core::option::Option::Some(::core::result::Result::Err(e)),
688                        };
689                        if let ::core::option::Option::Some(item) = item {
690                            self.0 = next_state;
691                            return ::core::option::Option::Some(::core::result::Result::Ok(item));
692                        }
693                        // no event, do we have a state?
694                        if let ::core::option::Option::Some(st) = next_state {
695                            // we do: try again!
696                            state = st;
697                            continue;
698                        } else {
699                            // we don't: end of iterator!
700                            self.0 = ::core::option::Option::None;
701                            return ::core::option::Option::None;
702                        }
703                    }
704                }
705            }
706
707            impl<#item_iter_ty_lifetime> #item_iter_ty {
708                fn new(value: &#item_iter_ty_lifetime #input_ty) -> ::core::result::Result<Self, ::xso::error::Error> {
709                    #state_ty_ident::new(value).map(|ok| Self(::core::option::Option::Some(ok)))
710                }
711            }
712        })
713    }
714}
715
716/// Construct a path for an intradoc link from a given type.
717fn doc_link_path(ty: &Type) -> Option<String> {
718    match ty {
719        Type::Path(ref ty) => {
720            let (mut buf, offset) = match ty.qself {
721                Some(ref qself) => {
722                    let mut buf = doc_link_path(&qself.ty)?;
723                    buf.push_str("::");
724                    (buf, qself.position)
725                }
726                None => {
727                    let mut buf = String::new();
728                    if ty.path.leading_colon.is_some() {
729                        buf.push_str("::");
730                    }
731                    (buf, 0)
732                }
733            };
734            let last = ty.path.segments.len() - 1;
735            for i in offset..ty.path.segments.len() {
736                let segment = &ty.path.segments[i];
737                buf.push_str(&segment.ident.to_string());
738                if i < last {
739                    buf.push_str("::");
740                }
741            }
742            Some(buf)
743        }
744        _ => None,
745    }
746}
747
748/// Create a markdown snippet which references the given type as cleanly as
749/// possible.
750///
751/// This is used in documentation generation functions.
752///
753/// Not all types can be linked to; those which cannot be linked to will
754/// simply be wrapped in backticks.
755fn make_ty_ref(ty: &Type) -> String {
756    match doc_link_path(ty) {
757        Some(mut path) => {
758            path.reserve(4);
759            path.insert_str(0, "[`");
760            path.push_str("`]");
761            path
762        }
763        None => format!("`{}`", ty.to_token_stream()),
764    }
765}