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}