scale_info_legacy/
lookup_name.rs

1// Copyright (C) 2024 Parity Technologies (UK) Ltd. (admin@parity.io)
2// This file is a part of the scale-info-legacy crate.
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//         http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16//! This module provides a struct, [`LookupName`]. This struct represents a single concrete type
17//! that can be looked up in the [`crate::TypeRegistry`].
18
19use core::{cmp::Ordering, hash::Hash};
20
21use alloc::{
22    borrow::{Cow, ToOwned},
23    format,
24    string::{String, ToString},
25};
26use smallstr::SmallString;
27use smallvec::SmallVec;
28
29// Re-export errors in our public interface:
30pub use parser::{ParseError, ParseErrorKind};
31
32/// The name of a type that you'd like to query in the [`crate::TypeRegistry`]. Use
33/// [`LookupName::parse()`] to parse a string into a [`LookupName`], which can then be used
34/// to look up the associated details in the registry.
35///
36/// See [`crate::TypeRegistry::resolve_type()`] for a full example.
37///
38/// # Example
39///
40/// ```rust
41/// use scale_info_legacy::LookupName;
42///
43/// let sequence = LookupName::parse("Vec<(bool, u32)>").unwrap();
44/// let array = LookupName::parse("[u8; 32]").unwrap();
45/// let tuple = LookupName::parse("(bool, u32, Vec<String>)").unwrap();
46/// ```
47#[derive(Clone)]
48pub struct LookupName {
49    registry: Registry,
50    idx: usize,
51    // Setting this means that when we try to resolve this type, we'll
52    // look at types defined within the given pallet before considering
53    // any global types.
54    pallet: Option<String>,
55}
56
57impl Hash for LookupName {
58    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
59        LookupNameInner::hash(self.idx, &self.registry, state)
60    }
61}
62
63// We only implement this because `scale_type_resolver::TypeResolver` requires
64// type IDs to impl Default.
65impl Default for LookupName {
66    fn default() -> Self {
67        // Various methods expect the registry to have at least one type in it,
68        // so we set the type to be the empty unit type.
69        let unit_type = LookupNameInner::Unnamed { params: Params::new() };
70        Self { registry: Registry::from_iter([unit_type]), idx: 0, pallet: None }
71    }
72}
73
74impl PartialOrd for LookupName {
75    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
76        Some(self.cmp(other))
77    }
78}
79
80impl Ord for LookupName {
81    fn cmp(&self, other: &Self) -> Ordering {
82        if let o @ (Ordering::Greater | Ordering::Less) = self.pallet.cmp(&other.pallet) {
83            return o;
84        }
85
86        let a_idx = self.idx;
87        let a_registry = &self.registry;
88        let b_idx = other.idx;
89        let b_registry = &other.registry;
90
91        LookupNameInner::cmp(a_idx, a_registry, b_idx, b_registry)
92    }
93}
94
95impl PartialEq for LookupName {
96    fn eq(&self, other: &Self) -> bool {
97        if self.pallet != other.pallet {
98            return false;
99        }
100
101        let a_idx = self.idx;
102        let a_registry = &self.registry;
103        let b_idx = other.idx;
104        let b_registry = &other.registry;
105
106        LookupNameInner::eq(a_idx, a_registry, b_idx, b_registry)
107    }
108}
109
110impl Eq for LookupName {}
111
112impl core::fmt::Debug for LookupName {
113    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
114        write!(f, "{}", self.def())
115    }
116}
117
118impl core::fmt::Display for LookupName {
119    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
120        write!(f, "{}", self.def())
121    }
122}
123
124impl core::str::FromStr for LookupName {
125    type Err = ParseError;
126    fn from_str(s: &str) -> Result<Self, Self::Err> {
127        Self::parse(s)
128    }
129}
130
131impl core::convert::From<crate::InsertName> for LookupName {
132    fn from(value: crate::InsertName) -> Self {
133        let param_ids = value.params.iter().enumerate().map(|(idx, _)| idx + 1).collect();
134
135        let params_iter = value.params.into_iter().map(|param_name| LookupNameInner::Named {
136            name: param_name.into(),
137            params: Default::default(),
138        });
139
140        let registry_iter =
141            core::iter::once(LookupNameInner::Named { name: value.name.into(), params: param_ids })
142                .chain(params_iter);
143
144        LookupName { registry: SmallVec::from_iter(registry_iter), idx: 0, pallet: value.pallet }
145    }
146}
147
148impl core::convert::TryFrom<&str> for LookupName {
149    type Error = ParseError;
150    fn try_from(s: &str) -> Result<Self, Self::Error> {
151        Self::parse(s)
152    }
153}
154
155impl core::convert::TryFrom<String> for LookupName {
156    type Error = ParseError;
157    fn try_from(s: String) -> Result<Self, Self::Error> {
158        Self::parse(&s)
159    }
160}
161
162impl serde::Serialize for LookupName {
163    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
164    where
165        S: serde::Serializer,
166    {
167        serializer.serialize_str(&self.to_string())
168    }
169}
170
171impl<'de> serde::Deserialize<'de> for LookupName {
172    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
173    where
174        D: serde::Deserializer<'de>,
175    {
176        use serde::de::Error;
177        let s = <Cow<'de, str>>::deserialize(deserializer)?;
178        LookupName::parse(&s)
179            .map_err(|e| D::Error::custom(format!("Could not deserialize into LookupName: {e}")))
180    }
181}
182
183impl LookupName {
184    /// Parse an input string into a [`LookupName`].
185    pub fn parse(input: &str) -> Result<LookupName, ParseError> {
186        use yap::IntoTokens;
187        let mut tokens = input.into_tokens();
188        let mut registry = Registry::new();
189
190        parser::parse_type_name(&mut tokens, &mut registry)?;
191
192        Ok(LookupName {
193            // Registry must have at least 1 item in, and the last item
194            // we added is always the outermost one we want to point to.
195            idx: registry.len() - 1,
196            registry,
197            pallet: None,
198        })
199    }
200
201    /// Create a [`LookupName`] representing a tuple of the provided type names.
202    pub fn unnamed<'a>(input: impl IntoIterator<Item = &'a LookupName>) -> LookupName {
203        let mut name = LookupName {
204            registry: SmallVec::from_iter([
205                // This is just a placeholder; we'll replace it at the bottom.
206                LookupNameInner::Unnamed { params: SmallVec::new() },
207            ]),
208            idx: 0,
209            pallet: None,
210        };
211
212        // Put the content of each of the given names into our new registry
213        let ids = input.into_iter().map(|id| name.insert_def(id.def(), &[])).collect();
214
215        // Overwrite our "entry point" to point to each of these inserted Ids.
216        name.registry[0] = LookupNameInner::Unnamed { params: ids };
217        name
218    }
219
220    /// Create a [`LookupName`] representing an array of the provided lookup name with the given length.
221    pub fn array(inner: &LookupName, len: usize) -> LookupName {
222        let mut name = LookupName {
223            registry: SmallVec::from_iter([
224                // This is just a placeholder; we'll replace it at the bottom.
225                LookupNameInner::Array { param: 0, length: 0 },
226            ]),
227            idx: 0,
228            pallet: None,
229        };
230
231        let inner_idx = name.insert_def(inner.def(), &[]);
232        name.registry[0] = LookupNameInner::Array { param: inner_idx, length: len };
233        name
234    }
235
236    /// This will scope the lookup such that it can make use of types within the given pallet.
237    pub fn in_pallet(mut self, pallet_name: impl Into<String>) -> LookupName {
238        self.pallet = Some(pallet_name.into());
239        self
240    }
241
242    /// Return the name of this type, if there is one (ie it is not an unnamed type like a tuple or array).
243    /// The name of a type includes its path, if it has one.
244    pub fn name(&self) -> Option<&str> {
245        match self.def() {
246            LookupNameDef::Named(named) => Some(named.name),
247            _ => None,
248        }
249    }
250
251    /// The pallet that we should perform this type lookup in.
252    pub(crate) fn pallet(&self) -> Option<&str> {
253        self.pallet.as_deref()
254    }
255
256    /// Remove the pallet value from the type name, leaving `None` in its place.
257    pub(crate) fn take_pallet(&mut self) -> Option<String> {
258        self.pallet.take()
259    }
260
261    /// Substitute a named type with another. This is useful if we have a type name
262    /// like `Vec<T>` and want to turn it into a concrete type like `Vec<u32>`.
263    pub(crate) fn with_substitution(
264        mut self,
265        ident: &str,
266        replacement: LookupNameDef<'_>,
267    ) -> LookupName {
268        let original_len = self.registry.len();
269
270        // These are all of the indexes we'll want to swap for something else:
271        let indexes_to_replace: SmallVec<[_;2]> = self.registry
272            .iter()
273            .enumerate()
274            .filter(|(_, ty)| matches!(ty, LookupNameInner::Named { name, params } if params.is_empty() && name == ident))
275            .map(|(idx,_)| idx)
276            .collect();
277
278        // Nothing to do; return unchanged:
279        if indexes_to_replace.is_empty() {
280            return self;
281        }
282
283        // Insert the replacement type, returning the index to it:
284        let replacement_idx = self.insert_def(replacement, &indexes_to_replace);
285
286        // A couple of helpers to replace any params found in indexes_to_replace with the replacement_idx.
287        let update_param = |param: &mut usize| {
288            if indexes_to_replace.contains(param) {
289                *param = replacement_idx;
290            }
291        };
292        let update_params = |params: &mut Params| {
293            for param in params.iter_mut() {
294                update_param(param);
295            }
296        };
297
298        // Update _existing_ types pointing to one of the `indexes_to_replace` to point to this new one.
299        for (idx, inner) in self.registry.iter_mut().enumerate() {
300            if idx >= original_len {
301                // Ignore any new types we added.
302                break;
303            }
304            if indexes_to_replace.contains(&idx) {
305                // Ignore any types we may have updated (because we may reuse these indexes).
306                continue;
307            }
308
309            match inner {
310                LookupNameInner::Named { params, .. } => update_params(params),
311                LookupNameInner::Unnamed { params } => update_params(params),
312                LookupNameInner::Array { param, .. } => update_param(param),
313            }
314        }
315
316        // If the Name index itself needs updating, also do this:
317        update_param(&mut self.idx);
318
319        self
320    }
321
322    /// Fetch the definition of this type.
323    pub(crate) fn def(&self) -> LookupNameDef<'_> {
324        self.def_at(self.idx)
325    }
326
327    /// Insert a foreign [`LookupNameDef`] into this type's registry, returning the index that it was inserted at.
328    fn insert_def(&mut self, ty: LookupNameDef<'_>, free_idxs: &[usize]) -> usize {
329        let (idx, registry) = match ty {
330            LookupNameDef::Named(t) => (t.idx, &t.handle.registry),
331            LookupNameDef::Unnamed(t) => (t.idx, &t.handle.registry),
332            LookupNameDef::Array(t) => (t.idx, &t.handle.registry),
333        };
334
335        self.insert_entry_from_other_registry(idx, registry, &mut &*free_idxs)
336    }
337
338    /// Take a registry and valid index into it, and copy the relevant entries into our own registry,
339    /// returning the index at which the given entry ended up.
340    fn insert_entry_from_other_registry(
341        &mut self,
342        idx: usize,
343        registry: &Registry,
344        free_idxs: &mut &[usize],
345    ) -> usize {
346        let idx_to_use = free_idxs.first().map(|idx| {
347            *free_idxs = &free_idxs[1..];
348            *idx
349        });
350
351        let new_inner = match &registry.get(idx).expect("type index used which doesn't exist") {
352            LookupNameInner::Named { name, params } => {
353                let new_params = params
354                    .iter()
355                    .map(|idx: &usize| {
356                        self.insert_entry_from_other_registry(*idx, registry, free_idxs)
357                    })
358                    .collect();
359                LookupNameInner::Named { name: name.clone(), params: new_params }
360            }
361            LookupNameInner::Unnamed { params } => {
362                let new_params = params
363                    .iter()
364                    .map(|idx: &usize| {
365                        self.insert_entry_from_other_registry(*idx, registry, free_idxs)
366                    })
367                    .collect();
368                LookupNameInner::Unnamed { params: new_params }
369            }
370            LookupNameInner::Array { param, length } => {
371                let new_param = self.insert_entry_from_other_registry(*param, registry, free_idxs);
372                LookupNameInner::Array { param: new_param, length: *length }
373            }
374        };
375
376        // Reuse an existing space if possible, else push a new item to the end:
377        if let Some(idx_to_use) = idx_to_use {
378            self.registry[idx_to_use] = new_inner;
379            idx_to_use
380        } else {
381            let new_idx = self.registry.len();
382            self.registry.push(new_inner);
383            new_idx
384        }
385    }
386
387    // Fetch (and expect to exist) a definition at some index.
388    fn def_at(&self, idx: usize) -> LookupNameDef<'_> {
389        let entry = self.registry.get(idx).expect("idx should exist in registry");
390
391        match entry {
392            LookupNameInner::Named { name, params } => {
393                LookupNameDef::Named(NamedTypeDef { idx, name, params, handle: self })
394            }
395            LookupNameInner::Unnamed { params } => {
396                LookupNameDef::Unnamed(UnnamedTypeDef { idx, params, handle: self })
397            }
398            LookupNameInner::Array { param, length } => LookupNameDef::Array(ArrayTypeDef {
399                idx,
400                param: *param,
401                length: *length,
402                handle: self,
403            }),
404        }
405    }
406}
407
408/// The definition of some type.
409#[derive(Debug, Copy, Clone)]
410pub enum LookupNameDef<'tn> {
411    /// Types like `Vec<T>`, `Foo` and `path::to::Bar<A,B>`, `i32`, `bool`
412    /// etc are _named_ types.
413    Named(NamedTypeDef<'tn>),
414    /// Tuples like `()` and `(Foo, Bar<A>)` are _unnamed_ types.
415    Unnamed(UnnamedTypeDef<'tn>),
416    /// Fixed length arrays like `[Bar; 32]` are _array_ types.
417    Array(ArrayTypeDef<'tn>),
418}
419
420impl<'a> core::fmt::Display for LookupNameDef<'a> {
421    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
422        match self {
423            LookupNameDef::Named(named) => {
424                write!(f, "{}", named.name())?;
425                if !named.params.is_empty() {
426                    write!(f, "<")?;
427                    let mut fst = true;
428                    for param in named.param_defs() {
429                        if !fst {
430                            write!(f, ", ")?;
431                        }
432                        fst = false;
433                        write!(f, "{}", param)?;
434                    }
435                    write!(f, ">")?;
436                }
437            }
438            LookupNameDef::Unnamed(unnamed) => {
439                write!(f, "(")?;
440                if !unnamed.params.is_empty() {
441                    let mut fst = true;
442                    for param in unnamed.param_defs() {
443                        if !fst {
444                            write!(f, ", ")?;
445                        }
446                        fst = false;
447                        write!(f, "{}", param)?;
448                    }
449                }
450                write!(f, ")")?;
451            }
452            LookupNameDef::Array(array) => {
453                write!(f, "[{}; {}]", array.param_def(), array.length())?;
454            }
455        }
456        Ok(())
457    }
458}
459
460impl<'tn> LookupNameDef<'tn> {
461    /// Convert this back into a [`LookupName`].
462    pub fn into_type_name(self) -> LookupName {
463        match self {
464            LookupNameDef::Named(v) => v.into_type_name(),
465            LookupNameDef::Unnamed(v) => v.into_type_name(),
466            LookupNameDef::Array(v) => v.into_type_name(),
467        }
468    }
469
470    #[cfg(test)]
471    fn unwrap_named(self) -> NamedTypeDef<'tn> {
472        match self {
473            LookupNameDef::Named(a) => a,
474            _ => panic!("Cannot unwrap '{self:?}' into an NamedName"),
475        }
476    }
477
478    #[cfg(test)]
479    fn unwrap_unnamed(self) -> UnnamedTypeDef<'tn> {
480        match self {
481            LookupNameDef::Unnamed(a) => a,
482            _ => panic!("Cannot unwrap '{self:?}' into an UnnamedName"),
483        }
484    }
485
486    #[cfg(test)]
487    fn unwrap_array(self) -> ArrayTypeDef<'tn> {
488        match self {
489            LookupNameDef::Array(a) => a,
490            _ => panic!("Cannot unwrap '{self:?}' into an ArrayName"),
491        }
492    }
493}
494
495/// The definition of a named type.
496#[derive(Debug, Copy, Clone)]
497pub struct NamedTypeDef<'tn> {
498    name: &'tn str,
499    params: &'tn Params,
500    handle: &'tn LookupName,
501    idx: usize,
502}
503
504impl<'tn> NamedTypeDef<'tn> {
505    /// Convert this back into a [`LookupName`].
506    pub fn into_type_name(self) -> LookupName {
507        LookupName {
508            pallet: self.handle.pallet.to_owned(),
509            registry: self.handle.registry.clone(),
510            idx: self.idx,
511        }
512    }
513
514    /// The type name.
515    pub fn name(&self) -> &'tn str {
516        self.name
517    }
518
519    /// Iterate over the type parameter definitions.
520    pub fn param_defs(&self) -> impl Iterator<Item = LookupNameDef<'tn>> {
521        self.params.iter().map(|idx| self.handle.def_at(*idx))
522    }
523}
524
525/// The definition of an unnamed type.
526#[derive(Debug, Copy, Clone)]
527pub struct UnnamedTypeDef<'tn> {
528    params: &'tn Params,
529    handle: &'tn LookupName,
530    idx: usize,
531}
532
533impl<'tn> UnnamedTypeDef<'tn> {
534    /// Convert this back into a [`LookupName`].
535    pub fn into_type_name(self) -> LookupName {
536        LookupName {
537            pallet: self.handle.pallet.to_owned(),
538            registry: self.handle.registry.clone(),
539            idx: self.idx,
540        }
541    }
542
543    /// Iterate over the type parameter definitions
544    pub fn param_defs(&self) -> impl ExactSizeIterator<Item = LookupNameDef<'tn>> {
545        self.params.iter().map(|idx| self.handle.def_at(*idx))
546    }
547}
548
549/// The definition of an array type.
550#[derive(Debug, Copy, Clone)]
551pub struct ArrayTypeDef<'tn> {
552    param: usize,
553    length: usize,
554    handle: &'tn LookupName,
555    idx: usize,
556}
557
558impl<'tn> ArrayTypeDef<'tn> {
559    /// Convert this back into a [`LookupName`].
560    pub fn into_type_name(self) -> LookupName {
561        LookupName {
562            pallet: self.handle.pallet.to_owned(),
563            registry: self.handle.registry.clone(),
564            idx: self.idx,
565        }
566    }
567
568    /// The array length
569    pub fn length(&self) -> usize {
570        self.length
571    }
572    /// The array type parameter.
573    pub fn param_def(&self) -> LookupNameDef<'tn> {
574        self.handle.def_at(self.param)
575    }
576}
577
578// Internal types used:
579type Registry = SmallVec<[LookupNameInner; 2]>;
580type Params = SmallVec<[usize; 2]>;
581type NameStr = SmallString<[u8; 16]>;
582
583/// The internal representation of some type name.
584#[derive(Clone, Debug)]
585pub enum LookupNameInner {
586    /// Types like `Vec<T>`, `Foo` and `path::to::Bar<A,B>`, `i32`, `bool`
587    /// etc are _named_ types.
588    Named {
589        /// The name of the type (eg Vec, i32, bool).
590        name: NameStr,
591        /// Each of the generic parameters, if any, associated with the type.
592        params: Params,
593    },
594    /// Tuples like `()` and `(Foo, Bar<A>)` are _unnamed_ types.
595    Unnamed {
596        /// Each of the types in the tuple.
597        params: Params,
598    },
599    /// Fixed length arrays like `[Bar; 32]` are _array_ types.
600    Array {
601        /// The type in the array.
602        param: usize,
603        /// The fixed length of the array.
604        length: usize,
605    },
606}
607
608// If the orderings match, do nothing, else return the ordering.
609macro_rules! ord_eq {
610    ($a:expr) => {
611        if let o @ (Ordering::Greater | Ordering::Less) = $a {
612            return o;
613        }
614    };
615    ($a:expr, $b:expr) => {
616        if let o @ (Ordering::Greater | Ordering::Less) = $a.cmp(&$b) {
617            return o;
618        }
619    };
620}
621
622impl LookupNameInner {
623    fn cmp(
624        a_idx: usize,
625        a_registry: &Registry,
626        b_idx: usize,
627        b_registry: &Registry,
628    ) -> core::cmp::Ordering {
629        let a = &a_registry[a_idx];
630        let b = &b_registry[b_idx];
631
632        match (a, b) {
633            // Same variants; compare ordering of each field:
634            (
635                LookupNameInner::Named { name: a_name, params: a_params },
636                LookupNameInner::Named { name: b_name, params: b_params },
637            ) => {
638                ord_eq!(a_name, b_name);
639                ord_eq!(a_params.len(), b_params.len());
640
641                for (a_param, b_param) in a_params.iter().zip(b_params.iter()) {
642                    ord_eq!(LookupNameInner::cmp(*a_param, a_registry, *b_param, b_registry));
643                }
644            }
645            (
646                LookupNameInner::Unnamed { params: a_params },
647                LookupNameInner::Unnamed { params: b_params },
648            ) => {
649                ord_eq!(a_params.len(), b_params.len());
650
651                for (a_param, b_param) in a_params.iter().zip(b_params.iter()) {
652                    ord_eq!(LookupNameInner::cmp(*a_param, a_registry, *b_param, b_registry));
653                }
654            }
655            (
656                LookupNameInner::Array { param: a_param, length: a_len },
657                LookupNameInner::Array { param: b_param, length: b_len },
658            ) => {
659                ord_eq!(a_len, b_len);
660                ord_eq!(LookupNameInner::cmp(*a_param, a_registry, *b_param, b_registry));
661            }
662            // Different variants; arbitrary ordering between them:
663            (LookupNameInner::Named { .. }, _) => return Ordering::Greater,
664            (LookupNameInner::Unnamed { .. }, _) => return Ordering::Greater,
665            (LookupNameInner::Array { .. }, _) => return Ordering::Greater,
666        }
667        Ordering::Equal
668    }
669
670    fn eq(a_idx: usize, a_registry: &Registry, b_idx: usize, b_registry: &Registry) -> bool {
671        LookupNameInner::cmp(a_idx, a_registry, b_idx, b_registry).is_eq()
672    }
673
674    fn hash<H: core::hash::Hasher>(idx: usize, registry: &Registry, state: &mut H) {
675        let inner = &registry[idx];
676        match inner {
677            LookupNameInner::Array { param, length } => {
678                0u8.hash(state);
679                LookupNameInner::hash(*param, registry, state);
680                length.hash(state);
681            }
682            LookupNameInner::Named { name, params } => {
683                1u8.hash(state);
684                name.hash(state);
685                for param in params {
686                    LookupNameInner::hash(*param, registry, state);
687                }
688            }
689            LookupNameInner::Unnamed { params } => {
690                2u8.hash(state);
691                for param in params {
692                    LookupNameInner::hash(*param, registry, state);
693                }
694            }
695        }
696    }
697}
698
699// Logic for parsing strings into type names.
700mod parser {
701    use super::*;
702    use yap::{types::StrTokens, TokenLocation, Tokens};
703
704    /// An error that can be emitted as the result of trying to parse a string into a [`LookupName`].
705    #[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
706    #[error("Error parsing string into type name at character {loc}: {err}")]
707    pub struct ParseError {
708        /// Index into the string denoting the position of the error.
709        pub loc: usize,
710        /// More information about the error.
711        pub err: ParseErrorKind,
712    }
713
714    impl ParseError {
715        /// Construct a new `ParseError` for tokens at the given location.
716        pub fn new_at<E: Into<ParseErrorKind>>(err: E, loc: usize) -> Self {
717            Self { loc, err: err.into() }
718        }
719    }
720
721    /// The kind of error that happened attempting to parse a string into a [`LookupName`].
722    #[allow(missing_docs)]
723    #[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
724    pub enum ParseErrorKind {
725        #[error("The string did not look like a type name at all.")]
726        InvalidName,
727        #[error("A closing `)` was missing when attempting to parse a tuple type name.")]
728        ClosingParenMissing,
729        #[error(
730            "A closing `>` was missing when attempting to parse the generics of a named type."
731        )]
732        ClosingAngleBracketMissing,
733        #[error("A closing `]` was missing when attempting to parse an array type.")]
734        ClosingSquareBracketMissing,
735        #[error("The length of the array is invalid; expecting an unsigned integer.")]
736        InvalidUnsignedInt,
737    }
738
739    pub fn parse_type_name(
740        input: &mut StrTokens<'_>,
741        registry: &mut Registry,
742    ) -> Result<(), ParseError> {
743        let loc = input.location();
744        try_parse_type_name(input, registry)
745            .unwrap_or_else(|| Err(ParseError::new_at(ParseErrorKind::InvalidName, loc.offset())))
746    }
747
748    fn try_parse_type_name(
749        input: &mut StrTokens<'_>,
750        registry: &mut Registry,
751    ) -> Option<Result<(), ParseError>> {
752        yap::one_of!(input;
753            parse_unnamed_into_type_name(input, registry),
754            parse_array_into_type_name(input, registry),
755            parse_named_into_type_name(input, registry),
756            parse_slice_into_type_name(input, registry),
757        )
758    }
759
760    // Parse a named type like Vec<bool>, i32, bool, Foo.
761    fn parse_named_into_type_name(
762        input: &mut StrTokens<'_>,
763        registry: &mut Registry,
764    ) -> Option<Result<(), ParseError>> {
765        let name = parse_path(input);
766        if name.is_empty() {
767            return None;
768        }
769
770        skip_whitespace(input);
771        if !input.token('<') {
772            // No generics; just add the name to the registry
773            registry.push(LookupNameInner::Named {
774                name: NameStr::from_str(&name),
775                params: Params::new(),
776            });
777            return Some(Ok(()));
778        }
779
780        let params = match parse_comma_separated_type_names(input, registry) {
781            Ok(params) => params,
782            Err(err) => return Some(Err(err)),
783        };
784
785        if !input.token('>') {
786            let loc = input.location().offset();
787            Some(Err(ParseError::new_at(ParseErrorKind::ClosingAngleBracketMissing, loc)))
788        } else {
789            registry.push(LookupNameInner::Named { name: NameStr::from_str(&name), params });
790            Some(Ok(()))
791        }
792    }
793
794    // Parse an unnamed (tuple) type like () or (bool, Foo, Bar<T>).
795    fn parse_unnamed_into_type_name(
796        input: &mut StrTokens<'_>,
797        registry: &mut Registry,
798    ) -> Option<Result<(), ParseError>> {
799        if !input.token('(') {
800            return None;
801        }
802
803        let params = match parse_comma_separated_type_names(input, registry) {
804            Ok(params) => params,
805            Err(err) => return Some(Err(err)),
806        };
807
808        if !input.token(')') {
809            let loc = input.location().offset();
810            Some(Err(ParseError::new_at(ParseErrorKind::ClosingParenMissing, loc)))
811        } else {
812            registry.push(LookupNameInner::Unnamed { params });
813            Some(Ok(()))
814        }
815    }
816
817    // Parse a fixed length array like [Foo; 32].
818    fn parse_array_into_type_name(
819        input: &mut StrTokens<'_>,
820        registry: &mut Registry,
821    ) -> Option<Result<(), ParseError>> {
822        if !input.token('[') {
823            return None;
824        }
825
826        skip_whitespace(input);
827        let param = match parse_type_name(input, registry) {
828            Ok(()) => registry.len() - 1,
829            Err(e) => return Some(Err(e)),
830        };
831
832        skip_whitespace(input);
833        input.token(';');
834        skip_whitespace(input);
835
836        let loc = input.location().offset();
837        let length: usize =
838            match input.take_while(|toks| toks.is_numeric()).parse::<usize, String>() {
839                Ok(n) => n,
840                Err(_) => {
841                    return Some(Err(ParseError::new_at(ParseErrorKind::InvalidUnsignedInt, loc)))
842                }
843            };
844
845        if !input.token(']') {
846            let loc = input.location().offset();
847            Some(Err(ParseError::new_at(ParseErrorKind::ClosingSquareBracketMissing, loc)))
848        } else {
849            registry.push(LookupNameInner::Array { param, length });
850            Some(Ok(()))
851        }
852    }
853
854    // Parse a slice like &[u8] or &[Foo] (this is very rare but appears in some old metadatas).
855    // These are treated as Vecs and parsed as such.
856    fn parse_slice_into_type_name(
857        input: &mut StrTokens<'_>,
858        registry: &mut Registry,
859    ) -> Option<Result<(), ParseError>> {
860        if !input.tokens("&[".chars()) {
861            return None;
862        }
863
864        skip_whitespace(input);
865        let param = match parse_type_name(input, registry) {
866            Ok(()) => registry.len() - 1,
867            Err(e) => return Some(Err(e)),
868        };
869        skip_whitespace(input);
870
871        if !input.token(']') {
872            let loc = input.location().offset();
873            Some(Err(ParseError::new_at(ParseErrorKind::ClosingSquareBracketMissing, loc)))
874        } else {
875            registry.push(LookupNameInner::Named {
876                name: NameStr::from_str("Vec"),
877                params: SmallVec::from_iter([param]),
878            });
879            Some(Ok(()))
880        }
881    }
882
883    // Parse a list of type names like Foo,Bar,usize. An empty list is allowed.
884    fn parse_comma_separated_type_names(
885        input: &mut StrTokens<'_>,
886        registry: &mut Registry,
887    ) -> Result<Params, ParseError> {
888        skip_whitespace(input);
889
890        let mut params_iter = input.sep_by(
891            |toks| {
892                // Try to parse a type name:
893                let res = try_parse_type_name(toks, registry)?;
894                // If successful, type name will be last item in registry:
895                Some(res.map(|()| registry.len() - 1))
896            },
897            |toks| toks.surrounded_by(|toks| toks.token(','), |toks| skip_whitespace(toks)),
898        );
899
900        let mut params = Params::new();
901        for res in params_iter.as_iter() {
902            let idx = res?;
903            params.push(idx);
904        }
905
906        skip_whitespace(input);
907        // Allow trailing comma but don't mandate it (ie we don't check the bool).
908        input.token(',');
909        skip_whitespace(input);
910
911        Ok(params)
912    }
913
914    // Parse the name/path of a type like `Foo`` or `a::b::Foo`.
915    fn parse_path<'a>(input: &mut StrTokens<'a>) -> Cow<'a, str> {
916        let path_str = str_slice_from(input, |toks| {
917            toks.sep_by(
918                |t| {
919                    // Handle paths like the '<Foo as Bar>' in <Foo as Bar>::Name.
920                    // We just count <'s and >'s and allow anything inside right now.
921                    if t.peek()? == '<' {
922                        let mut counter = 0;
923                        while let Some(tok) = t.next() {
924                            if tok == '<' {
925                                counter += 1;
926                            } else if tok == '>' {
927                                counter -= 1;
928                                if counter == 0 {
929                                    return Some(());
930                                }
931                            }
932                        }
933                    }
934
935                    // First char should exist and be a letter or underscore.
936                    let fst_char = t.next()?;
937                    if !(fst_char.is_alphabetic() || fst_char == '_') {
938                        return None;
939                    }
940                    // Rest can be letters or numbers or underscores.
941                    t.skip_while(|c| c.is_alphanumeric() || *c == '_');
942                    Some(())
943                },
944                |t| {
945                    // Our separator is `::`. Whitespace is allowed.
946                    t.surrounded_by(|t| t.tokens("::".chars()), |t| skip_whitespace(t))
947                },
948            )
949            .consume();
950        });
951
952        normalize_whitespace(path_str)
953    }
954
955    // It's possible that we can see type names like this:
956    //
957    // <Foo \nas   Bar>::path ::to :: SomeType
958    //
959    // We want to normalize those typenames to be more like this:
960    //
961    // <Foo as Bar>::path::to::SomeType
962    //
963    // This is done in two steps.
964    // 1. Turn multiple whitespaces into one space (which mainly resolves
965    //    the bit in '<>'s).
966    // 2. Remove any whitespace from the part of the path after any '>'.
967    //
968    // Public only so that it can be tested with our other tests.
969    pub fn normalize_whitespace(str: &str) -> Cow<'_, str> {
970        // Split <Foo as Bar>::some::Path into '<Foo as Bar>' and '::some::Path'
971        let idx = idx_after_closing_angle_bracket(&mut str.chars()).unwrap_or(0);
972        let trait_as_part = &str[0..idx];
973        let path_part = &str[idx..];
974
975        // Check to see if we need to change anything..
976
977        // - We need to normalize at least 1 whitespace char to ' '.
978        let change_in_trait_as_part = trait_as_part.chars().any(|c| c.is_whitespace() && c != ' ');
979        // - We need to remove N whitespaces in the <Foo as Bar> part.
980        let remove_in_trait_as_part = trait_as_part
981            .chars()
982            .zip(trait_as_part.chars().skip(1))
983            .filter(|(a, b)| a.is_whitespace() && b.is_whitespace())
984            .count();
985        // - We need to remove N whitespaces in the ::path::to::Foo part.
986        let remove_in_path_part = path_part.chars().filter(|c| c.is_whitespace()).count();
987
988        // If no changes to be made then return as is.
989        if remove_in_trait_as_part == 0 && remove_in_path_part == 0 && !change_in_trait_as_part {
990            return Cow::Borrowed(str);
991        }
992
993        let mut new_s =
994            String::with_capacity(str.len() - remove_in_path_part - remove_in_trait_as_part);
995
996        // Replace whitespaces in "<Trait as Bar>" section for 1 space.
997        let mut prev_is_whitespace = false;
998        for c in trait_as_part.chars() {
999            if c.is_whitespace() {
1000                if !prev_is_whitespace {
1001                    prev_is_whitespace = true;
1002                    new_s.push(' ');
1003                }
1004            } else {
1005                prev_is_whitespace = false;
1006                new_s.push(c);
1007            }
1008        }
1009
1010        // Remove whitespaces in "foo::bar::Wibble" section.
1011        path_part.chars().filter(|c| !c.is_whitespace()).for_each(|c| new_s.push(c));
1012
1013        Cow::Owned(new_s)
1014    }
1015
1016    // given eg <<Foo as bar>::Wibble as Bob>::path::To, find the first index of '::path::To'.
1017    fn idx_after_closing_angle_bracket(s: &mut impl Iterator<Item = char>) -> Option<usize> {
1018        let mut idx = 0;
1019        let mut counter = 0;
1020        for tok in s {
1021            idx += 1;
1022            if tok == '<' {
1023                counter += 1;
1024            } else if tok == '>' {
1025                counter -= 1;
1026                if counter == 0 {
1027                    return Some(idx);
1028                }
1029            }
1030        }
1031        None
1032    }
1033
1034    // Skip over any whitespace, ignoring it.
1035    fn skip_whitespace(input: &mut StrTokens<'_>) {
1036        input.skip_while(|t| t.is_whitespace());
1037    }
1038
1039    // Return the string slice that encompasses the provided parsing function given.
1040    fn str_slice_from<'a, F>(input: &mut StrTokens<'a>, f: F) -> &'a str
1041    where
1042        F: FnOnce(&mut StrTokens<'a>),
1043    {
1044        let before = input.remaining();
1045        f(input);
1046        let leftover = input.remaining().len();
1047
1048        &before[..before.len() - leftover]
1049    }
1050}
1051
1052#[cfg(test)]
1053mod test {
1054    use super::*;
1055    use alloc::borrow::ToOwned;
1056    use alloc::string::ToString;
1057    use alloc::vec;
1058    use alloc::vec::Vec;
1059
1060    fn expect_parse(input: &str) -> LookupName {
1061        match LookupName::parse(input) {
1062            Ok(tn) => tn,
1063            Err(e) => panic!("parsing '{input}' failed: {e}"),
1064        }
1065    }
1066
1067    fn expect_parse_fail(input: &str) {
1068        match LookupName::parse(input) {
1069            Ok(tn) => panic!("parsing '{input}' is expected to have failed, but got {tn:?}"),
1070            Err(_e) => {}
1071        }
1072    }
1073
1074    #[test]
1075    fn basic_eq_and_hash_works() {
1076        let cmps = [
1077            // Slices are treated identically to vecs
1078            (expect_parse("&[u8]"), expect_parse("Vec<u8>"), true),
1079            (expect_parse("&[Foo]"), expect_parse("Vec<Foo>"), true),
1080            // basic named types
1081            (expect_parse("path::to::Foo"), expect_parse("path::to::Foo"), true),
1082            (expect_parse("Foo<u8>"), expect_parse("Foo<u8>"), true),
1083            (expect_parse("Foo<u8>"), expect_parse("Foo<bool>"), false),
1084            (expect_parse("Foo<u8>"), expect_parse("Foo<u8, bool>"), false),
1085            (expect_parse("path::to::Foo").in_pallet("bar"), expect_parse("path::to::Foo"), false),
1086            (
1087                expect_parse("path::to::Foo").in_pallet("bar"),
1088                expect_parse("path::to::Foo").in_pallet("bar"),
1089                true,
1090            ),
1091            (
1092                expect_parse("path::for::Foo").in_pallet("bar"),
1093                expect_parse("path::to::Foo").in_pallet("bar"),
1094                false,
1095            ),
1096            (expect_parse("path::for::Foo"), expect_parse("path::to::Foo"), false),
1097            // arrays
1098            (expect_parse("[u8; 32]"), expect_parse("[u8; 32]"), true),
1099            (expect_parse("[u8; 32]"), expect_parse("[u8; 28]"), false),
1100            (expect_parse("[u8; 32]"), expect_parse("[u16; 32]"), false),
1101            // unnameds
1102            (expect_parse("()"), expect_parse("()"), true),
1103            (expect_parse("(bool,)"), expect_parse("(bool,)"), true),
1104            (expect_parse("(char, u8, String)"), expect_parse("(char, u8, String)"), true),
1105            (expect_parse("(char, u8, String)"), expect_parse("(char, u8, String, bool)"), false),
1106            (expect_parse("(u8, char, String)"), expect_parse("(char, u8, String)"), false),
1107        ];
1108
1109        for (a, b, expected) in cmps {
1110            assert_eq!(a == b, expected, "{a} should equal {b}: {expected}");
1111
1112            // if the types are supposed to be equal, hashes should be equal too.
1113            if expected {
1114                // Easiest way to check hashes is to see if two items hash to the same
1115                // location in a set. If hashes are different then locations _probably_ will be too.
1116                // Pre-init the HashSet with a capacity that should limit collision likelihood.
1117                // We could find a deterministic hasher and just check the raw hash values which
1118                // would be better but more complicated.
1119                let mut set = hashbrown::HashSet::with_capacity(1024);
1120                set.insert(&a);
1121                set.insert(&b);
1122                assert_eq!(set.len(), 1, "hash mismatch between {a} and {b}");
1123            }
1124        }
1125    }
1126
1127    #[test]
1128    fn eq_works_with_different_registries() {
1129        // These two types have differently ordered registries but
1130        // are actually the same type and so should be equal.
1131        let a = LookupName {
1132            registry: SmallVec::from_iter([
1133                LookupNameInner::Named { name: "Foo".into(), params: SmallVec::from_iter([1]) },
1134                LookupNameInner::Array { param: 2, length: 32 },
1135                LookupNameInner::Unnamed { params: SmallVec::from_iter([]) },
1136            ]),
1137            idx: 0,
1138            pallet: None,
1139        };
1140        let b = LookupName {
1141            registry: SmallVec::from_iter([
1142                LookupNameInner::Array { param: 1, length: 32 },
1143                LookupNameInner::Unnamed { params: SmallVec::from_iter([]) },
1144                LookupNameInner::Named { name: "Foo".into(), params: SmallVec::from_iter([0]) },
1145                // this type isn't referenced so should be ignored:
1146                LookupNameInner::Array { param: 0, length: 128 },
1147            ]),
1148            idx: 2,
1149            pallet: None,
1150        };
1151
1152        assert_eq!(a, b);
1153
1154        // Check that these items hash the same even though they are different internally.
1155        let mut set = hashbrown::HashSet::with_capacity(1024);
1156        set.insert(&a);
1157        set.insert(&b);
1158        assert_eq!(set.len(), 1, "hash mismatch between {a} and {b}");
1159    }
1160
1161    #[test]
1162    fn parse_succeeds() {
1163        expect_parse("()");
1164        expect_parse("(Foo)"); // Prob don't need to allow this but hey.
1165        expect_parse("(Foo,)");
1166        expect_parse("(Foo, usize,    i32)");
1167        expect_parse("(a,b,c,)");
1168
1169        expect_parse("path::to::Foo"); // paths should work.
1170        expect_parse("path_with_underscore::to::Foo"); // paths with underscores should work.
1171        expect_parse("_path_starting_underscore::to::Foo"); // paths with underscores should work.
1172        expect_parse("<Wibble as Bar<u32>>::to::Foo"); // paths should work.
1173        expect_parse("<Wibble as Bar<u32>> ::to::\n Foo"); // paths should work with spaces in
1174        expect_parse("Foo");
1175        expect_parse("Foo<>");
1176        expect_parse("Foo<A>");
1177        expect_parse("Foo<A, b,   (), (Wibble)>");
1178
1179        expect_parse("[usize;32]");
1180        expect_parse("[a::b::Foo<T,A,B> ;32]");
1181        expect_parse("[bool;    32]");
1182
1183        expect_parse("&[bool]");
1184        expect_parse("&[ u8]");
1185        expect_parse("&[a::b::Foo<T,A,B> ]");
1186    }
1187
1188    #[test]
1189    fn parse_fails() {
1190        // Numbers can't come first in identifiers.
1191        expect_parse_fail("3thing");
1192        expect_parse_fail("(bool,3)");
1193
1194        // Arrays need a number second.
1195        expect_parse_fail("[usize; Foo]");
1196
1197        // Brackets must be closed
1198        expect_parse_fail("(Foo, Bar");
1199        expect_parse_fail("[Foo; 32");
1200        expect_parse_fail("Foo<A, B");
1201    }
1202
1203    #[test]
1204    fn with_substitution_works() {
1205        // Tuple with 4 entries:
1206        // - The original type name.
1207        // - The ident we want to replace with something else.
1208        // - The thing to replace the ident with.
1209        // - The expected type name after replacement.
1210        let cases = [
1211            ("Foo<T>", "T", "(A,B,C)", "Foo<(A, B, C)>"),
1212            ("T", "T", "Vec<u64>", "Vec<u64>"),
1213            ("(T, T, u32, T, T)", "T", "[u64; 3]", "([u64; 3], [u64; 3], u32, [u64; 3], [u64; 3])"),
1214            ("Vec<T>", "T", "U", "Vec<U>"),
1215            ("Foo<T, (A, [T; 32])>", "T", "U", "Foo<U, (A, [U; 32])>"),
1216            ("Foo<T, (A, [T; 32])>", "T", "(A,B,C)", "Foo<(A, B, C), (A, [(A, B, C); 32])>"),
1217            // Don't match types with params; they are not generics so should be left alone:
1218            ("(T<A>, T)", "T", "U", "(T<A>, U)"),
1219        ];
1220
1221        for (original, find, replace_with, expected) in cases {
1222            let original_ty = LookupName::parse(original).unwrap();
1223            let replacement = LookupName::parse(replace_with).unwrap();
1224            let new_ty = original_ty.with_substitution(find, replacement.def());
1225            assert_eq!(expected, new_ty.to_string());
1226        }
1227    }
1228
1229    #[test]
1230    fn parses_into_expected_shape() {
1231        let tn = expect_parse("Foo");
1232        let def = tn.def().unwrap_named();
1233        assert!(def.name() == "Foo" && def.param_defs().count() == 0);
1234
1235        let tn = expect_parse("Foo<A>");
1236        let def = tn.def().unwrap_named();
1237        assert!(
1238            def.name() == "Foo" && def.param_defs().next().unwrap().unwrap_named().name() == "A"
1239        );
1240
1241        let tn = expect_parse("()");
1242        let def = tn.def().unwrap_unnamed();
1243        assert!(def.param_defs().count() == 0);
1244
1245        let tn = expect_parse("(bool, u32, Bar<A>)");
1246        let param_names: Vec<String> = tn
1247            .def()
1248            .unwrap_unnamed()
1249            .param_defs()
1250            .map(|p| p.unwrap_named().name().to_owned())
1251            .collect();
1252        assert_eq!(param_names, vec!["bool", "u32", "Bar"]);
1253
1254        let tn = expect_parse("[Foo; 16]");
1255        let def = tn.def().unwrap_array();
1256        assert!(def.length() == 16 && def.param_def().unwrap_named().name() == "Foo");
1257
1258        let tn = expect_parse("&[u8]");
1259        let def = tn.def().unwrap_named();
1260        assert!(
1261            def.name() == "Vec" && def.param_defs().next().unwrap().unwrap_named().name() == "u8"
1262        );
1263    }
1264
1265    #[test]
1266    fn parsing_complex_nested_type_works() {
1267        let tn = expect_parse("Foo<(Option<Wibble<[(u8, Bar);12],Compact<()>>>,bool)>");
1268
1269        // Foo
1270        let foo = tn.def().unwrap_named();
1271        assert_eq!(foo.name(), "Foo");
1272
1273        // Foo<@...@>
1274        let foo_params: Vec<_> = foo.param_defs().collect();
1275        assert_eq!(foo_params.len(), 1);
1276
1277        // Foo<@(...)@>
1278        let foo_tuple = foo_params[0].unwrap_unnamed();
1279        assert_eq!(foo_tuple.param_defs().count(), 2);
1280
1281        // Foo<(@...@)>
1282        let foo_tuple_params: Vec<_> = foo_tuple.param_defs().collect();
1283        assert_eq!(foo_tuple_params.len(), 2);
1284        assert_eq!(foo_tuple_params[0].unwrap_named().name(), "Option");
1285        assert_eq!(foo_tuple_params[1].unwrap_named().name(), "bool");
1286
1287        // Foo<(Option<@...@>)>
1288        let option_params: Vec<_> = foo_tuple_params[0].unwrap_named().param_defs().collect();
1289        assert_eq!(option_params.len(), 1);
1290
1291        // Foo<(Option<@Wibble<..>@>)>
1292        let wibble = option_params[0].unwrap_named();
1293        assert_eq!(wibble.name(), "Wibble");
1294
1295        // Foo<(Option<Wibble<@..@>>)>
1296        let wibble_params: Vec<_> = wibble.param_defs().collect();
1297        assert_eq!(wibble_params.len(), 2);
1298
1299        // Foo<(Option<Wibble<@[(u8, Bar);12)]@>>)>
1300        let arr = wibble_params[0].unwrap_array();
1301        assert_eq!(arr.length(), 12);
1302        assert_eq!(arr.param_def().unwrap_unnamed().param_defs().count(), 2);
1303    }
1304
1305    #[test]
1306    fn displaying_types_works() {
1307        let ty_name_strs = [
1308            "u32",
1309            "Foo",
1310            "Foo<T>",
1311            "Foo<A, B, C>",
1312            "[u8; 32]",
1313            "[Foo<A>; 32]",
1314            "()",
1315            "(A, B, C)",
1316            "Foo<(A, B, C<D>), [u8; 32], Bar<T>>",
1317        ];
1318
1319        for ty_name_str in ty_name_strs {
1320            let ty_name = LookupName::parse(ty_name_str).unwrap();
1321            assert_eq!(ty_name.to_string(), ty_name_str);
1322        }
1323    }
1324
1325    #[test]
1326    fn parsing_weird_paths_works() {
1327        let cases = [
1328            ("<Foo as Bar>::Item<A, B>", "<Foo as Bar>::Item<A, B>", vec!["A", "B"]),
1329            ("<Foo \tas \n\nBar>::Item", "<Foo as Bar>::Item", vec![]),
1330            (
1331                "<<Foo<Thing> \tas \n\nBar<A,B>> as Wibble>::Item",
1332                "<<Foo<Thing> as Bar<A,B>> as Wibble>::Item",
1333                vec![],
1334            ),
1335            ("_underscorefirst::Foo", "_underscorefirst::Foo", vec![]),
1336            ("underscore_in_path::Foo", "underscore_in_path::Foo", vec![]),
1337        ];
1338
1339        for (actual, expected, expected_params) in cases {
1340            let name = LookupName::parse(actual)
1341                .unwrap_or_else(|_| panic!("should be able to parse '{actual}'"));
1342
1343            let actual_params: Vec<String> =
1344                name.def().unwrap_named().param_defs().map(|p| p.to_string()).collect();
1345
1346            assert_eq!(actual_params, expected_params);
1347            assert_eq!(name.to_string(), expected);
1348        }
1349    }
1350
1351    #[test]
1352    fn normalize_whitespace_works() {
1353        let cases = &[
1354            // Remove spaces in path bit
1355            ("T:: Something", Cow::Owned("T::Something".to_string())),
1356            ("T ::Something", Cow::Owned("T::Something".to_string())),
1357            // Remove spaces in trait bit
1358            ("<Foo\n\t as \nBar>", Cow::Owned("<Foo as Bar>".to_string())),
1359            // Replace but not remove spaces in trait bit
1360            ("<Foo as\nBar>", Cow::Owned("<Foo as Bar>".to_string())),
1361            // Some complete examples.
1362            (
1363                "<T\t as \n\n\tfoo>:: path\n :: Something",
1364                Cow::Owned("<T as foo>::path::Something".to_string()),
1365            ),
1366            (
1367                "<<Foo   as\tbar>::Wibble \t \nas\nBob> ::path::\nTo",
1368                Cow::Owned("<<Foo as bar>::Wibble as Bob>::path::To".to_string()),
1369            ),
1370            (
1371                "<<Foo as bar>::Wibble as Bob>::path::To",
1372                Cow::Borrowed("<<Foo as bar>::Wibble as Bob>::path::To"),
1373            ),
1374        ];
1375
1376        for (input, output) in cases {
1377            assert_eq!(&parser::normalize_whitespace(input), output);
1378        }
1379    }
1380
1381    #[test]
1382    fn unnamed_lookup_name() {
1383        let entries = [
1384            LookupName::parse("u32").unwrap(),
1385            LookupName::parse("Foo<A, B, C>").unwrap(),
1386            LookupName::parse("(bool, char)").unwrap(),
1387            LookupName::parse("[u8; 32]").unwrap(),
1388        ];
1389
1390        let tuple = LookupName::unnamed(&entries);
1391        let expected = LookupName::parse("(u32, Foo<A,B,C>, (bool, char), [u8; 32])").unwrap();
1392
1393        assert_eq!(tuple, expected);
1394    }
1395
1396    #[test]
1397    fn array_lookup_name() {
1398        let inners = [
1399            LookupName::parse("u32").unwrap(),
1400            LookupName::parse("Foo<A, B, C>").unwrap(),
1401            LookupName::parse("(bool, char)").unwrap(),
1402            LookupName::parse("[u8; 32]").unwrap(),
1403        ];
1404
1405        for inner in inners {
1406            let array = LookupName::array(&inner, 32);
1407            let expected = LookupName::parse(&format!("[{inner}; 32]")).unwrap();
1408            assert_eq!(array, expected);
1409        }
1410    }
1411
1412    #[test]
1413    fn to_from_insert_name() {
1414        let cases = [
1415            "Foo<A, B, C>",
1416            "Bar",
1417            "foo::bar::Wibble",
1418            "foo::bar::Wibble<A>",
1419            "<Bar as Foo>::Something",
1420        ];
1421
1422        for case in cases {
1423            let lookup_name = LookupName::parse(case).expect("parses ok");
1424            let insert_name: crate::InsertName =
1425                lookup_name.clone().try_into().expect("converts to InsertName ok");
1426            let lookup_name_again: LookupName = insert_name.into();
1427
1428            assert_eq!(
1429                lookup_name, lookup_name_again,
1430                "mismatch between {lookup_name} and {lookup_name_again}"
1431            );
1432        }
1433    }
1434}