symbolic_common/
types.rs

1//! Common types and errors used in `symbolic`.
2
3use std::borrow::Cow;
4use std::fmt;
5use std::str;
6
7#[cfg(feature = "serde")]
8use serde::{Deserialize, Serialize};
9
10/// Represents a family of CPUs.
11///
12/// This is strongly connected to the [`Arch`] type, but reduces the selection to a range of
13/// families with distinct properties, such as a generally common instruction set and pointer size.
14///
15/// This enumeration is represented as `u32` for C-bindings and lowlevel APIs.
16///
17/// [`Arch`]: enum.Arch.html
18#[repr(u32)]
19#[non_exhaustive]
20#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Default)]
21pub enum CpuFamily {
22    /// Any other CPU family that is not explicitly supported.
23    #[default]
24    Unknown = 0,
25    /// 32-bit little-endian CPUs using the Intel 8086 instruction set, also known as `x86`.
26    Intel32 = 1,
27    /// 64-bit little-endian, also known as `x86_64`, now widely used by Intel and AMD.
28    Amd64 = 2,
29    /// 32-bit ARM.
30    Arm32 = 3,
31    /// 64-bit ARM (e.g. ARMv8-A).
32    Arm64 = 4,
33    /// 32-bit big-endian PowerPC.
34    Ppc32 = 5,
35    /// 64-bit big-endian PowerPC.
36    Ppc64 = 6,
37    /// 32-bit MIPS.
38    Mips32 = 7,
39    /// 64-bit MIPS.
40    Mips64 = 8,
41    /// ILP32 ABI on 64-bit ARM.
42    Arm64_32 = 9,
43    /// Virtual WASM 32-bit architecture.
44    Wasm32 = 10,
45}
46
47impl CpuFamily {
48    /// Returns the native pointer size.
49    ///
50    /// This commonly defines the size of CPU registers including the instruction pointer, and the
51    /// size of all pointers on the platform.
52    ///
53    /// This function returns `None` if the CPU family is unknown.
54    ///
55    /// # Examples
56    ///
57    /// ```
58    /// use symbolic_common::CpuFamily;
59    ///
60    /// assert_eq!(CpuFamily::Amd64.pointer_size(), Some(8));
61    /// assert_eq!(CpuFamily::Intel32.pointer_size(), Some(4));
62    /// ```
63    pub fn pointer_size(self) -> Option<usize> {
64        match self {
65            CpuFamily::Unknown => None,
66            CpuFamily::Wasm32 => Some(4),
67            CpuFamily::Amd64
68            | CpuFamily::Arm64
69            | CpuFamily::Ppc64
70            | CpuFamily::Mips64
71            | CpuFamily::Arm64_32 => Some(8),
72            CpuFamily::Intel32 | CpuFamily::Arm32 | CpuFamily::Ppc32 | CpuFamily::Mips32 => Some(4),
73        }
74    }
75
76    /// Returns instruction alignment if fixed.
77    ///
78    /// Some instruction sets, such as Intel's x86, use variable length instruction encoding.
79    /// Others, such as ARM, have fixed length instructions. This method returns `Some` for fixed
80    /// size instructions and `None` for variable-length instruction sizes.
81    ///
82    /// # Examples
83    ///
84    /// ```
85    /// use symbolic_common::CpuFamily;
86    ///
87    /// // variable length on x86_64:
88    /// assert_eq!(CpuFamily::Amd64.instruction_alignment(), None);
89    ///
90    /// // 4-byte alignment on all 64-bit ARM variants:
91    /// assert_eq!(CpuFamily::Arm64.instruction_alignment(), Some(4));
92    /// ```
93    pub fn instruction_alignment(self) -> Option<u64> {
94        match self {
95            CpuFamily::Wasm32 => Some(4),
96            CpuFamily::Arm32 => Some(2),
97            CpuFamily::Arm64 | CpuFamily::Arm64_32 => Some(4),
98            CpuFamily::Ppc32 | CpuFamily::Mips32 | CpuFamily::Mips64 => Some(4),
99            CpuFamily::Ppc64 => Some(8),
100            CpuFamily::Intel32 | CpuFamily::Amd64 => None,
101            CpuFamily::Unknown => None,
102        }
103    }
104
105    /// Returns the name of the instruction pointer register.
106    ///
107    /// The instruction pointer register holds a pointer to currrent code execution at all times.
108    /// This is a differrent register on each CPU family. The size of the value in this register is
109    /// specified by [`pointer_size`].
110    ///
111    /// Returns `None` if the CPU family is unknown.
112    ///
113    /// # Examples
114    ///
115    /// ```
116    /// use symbolic_common::CpuFamily;
117    ///
118    /// assert_eq!(CpuFamily::Amd64.ip_register_name(), Some("rip"));
119    /// ```
120    ///
121    /// [`pointer_size`]: enum.CpuFamily.html#method.pointer_size
122    pub fn ip_register_name(self) -> Option<&'static str> {
123        // NOTE: These values do not correspond to the register names defined in this file, but to
124        // the names exposed by breakpad. This mapping is implemented in `data_structures.cpp`.
125        match self {
126            CpuFamily::Intel32 => Some("eip"),
127            CpuFamily::Amd64 => Some("rip"),
128            CpuFamily::Arm32 | CpuFamily::Arm64 | CpuFamily::Arm64_32 => Some("pc"),
129            CpuFamily::Ppc32 | CpuFamily::Ppc64 => Some("srr0"),
130            CpuFamily::Mips32 | CpuFamily::Mips64 => Some("pc"),
131            CpuFamily::Wasm32 => None,
132            CpuFamily::Unknown => None,
133        }
134    }
135}
136
137/// An error returned for an invalid [`Arch`](enum.Arch.html).
138#[derive(Debug)]
139pub struct UnknownArchError;
140
141impl fmt::Display for UnknownArchError {
142    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
143        write!(f, "unknown architecture")
144    }
145}
146
147impl std::error::Error for UnknownArchError {}
148
149/// An enumeration of CPU architectures and variants.
150///
151/// The architectues are grouped into families, which can be retrieved by [`cpu_family`]. There are
152/// `*Unknown` variants for each architecture to maintain forward-compatibility. This allows to
153/// support architectures where the family is known but the subtype is not.
154///
155/// Each architecture has a canonical name, returned by [`Arch::name`]. Likewise, architectures can
156/// be parsed from their string names. In addition to that, in some cases aliases are supported. For
157/// instance, `"x86"` is aliased as `"i386"`.
158///
159/// This enumeration is represented as `u32` for C-bindings and lowlevel APIs. The values are
160/// grouped by CPU family for forward compatibility.
161///
162/// [`cpu_family`]: enum.Arch.html#method.cpu_family
163/// [`Arch::name`]: enum.Arch.html#method.name
164#[repr(u32)]
165#[non_exhaustive]
166#[allow(missing_docs)]
167#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Default)]
168pub enum Arch {
169    #[default]
170    Unknown = 0,
171    X86 = 101,
172    X86Unknown = 199,
173    Amd64 = 201,
174    Amd64h = 202,
175    Amd64Unknown = 299,
176    Arm = 301,
177    ArmV5 = 302,
178    ArmV6 = 303,
179    ArmV6m = 304,
180    ArmV7 = 305,
181    ArmV7f = 306,
182    ArmV7s = 307,
183    ArmV7k = 308,
184    ArmV7m = 309,
185    ArmV7em = 310,
186    ArmUnknown = 399,
187    Arm64 = 401,
188    Arm64V8 = 402,
189    Arm64e = 403,
190    Arm64Unknown = 499,
191    Ppc = 501,
192    Ppc64 = 601,
193    Mips = 701,
194    Mips64 = 801,
195    Arm64_32 = 901,
196    Arm64_32V8 = 902,
197    Arm64_32Unknown = 999,
198    Wasm32 = 1001,
199}
200
201impl Arch {
202    /// Creates an `Arch` from its `u32` representation.
203    ///
204    /// Returns `Arch::Unknown` for all unknown values.
205    ///
206    /// # Examples
207    ///
208    /// ```
209    /// use symbolic_common::Arch;
210    ///
211    /// // Will print "X86"
212    /// println!("{:?}", Arch::from_u32(101));
213    /// ```
214    pub fn from_u32(val: u32) -> Arch {
215        match val {
216            0 => Arch::Unknown,
217            1 | 101 => Arch::X86,
218            199 => Arch::X86Unknown,
219            2 | 201 => Arch::Amd64,
220            3 | 202 => Arch::Amd64h,
221            299 => Arch::Amd64Unknown,
222            4 | 301 => Arch::Arm,
223            5 | 302 => Arch::ArmV5,
224            6 | 303 => Arch::ArmV6,
225            7 | 304 => Arch::ArmV6m,
226            8 | 305 => Arch::ArmV7,
227            9 | 306 => Arch::ArmV7f,
228            10 | 307 => Arch::ArmV7s,
229            11 | 308 => Arch::ArmV7k,
230            12 | 309 => Arch::ArmV7m,
231            13 | 310 => Arch::ArmV7em,
232            399 => Arch::ArmUnknown,
233            14 | 401 => Arch::Arm64,
234            15 | 402 => Arch::Arm64V8,
235            16 | 403 => Arch::Arm64e,
236            499 => Arch::Arm64Unknown,
237            17 | 501 => Arch::Ppc,
238            18 | 601 => Arch::Ppc64,
239            701 => Arch::Mips,
240            801 => Arch::Mips64,
241            901 => Arch::Arm64_32,
242            902 => Arch::Arm64_32V8,
243            999 => Arch::Arm64_32Unknown,
244            1001 => Arch::Wasm32,
245            _ => Arch::Unknown,
246        }
247    }
248
249    /// Returns the CPU family of the CPU architecture.
250    ///
251    /// # Examples
252    ///
253    /// ```
254    /// use symbolic_common::Arch;
255    ///
256    /// // Will print "Intel32"
257    /// println!("{:?}", Arch::X86.cpu_family());
258    /// ```
259    pub fn cpu_family(self) -> CpuFamily {
260        match self {
261            Arch::Unknown => CpuFamily::Unknown,
262            Arch::X86 | Arch::X86Unknown => CpuFamily::Intel32,
263            Arch::Amd64 | Arch::Amd64h | Arch::Amd64Unknown => CpuFamily::Amd64,
264            Arch::Arm64 | Arch::Arm64V8 | Arch::Arm64e | Arch::Arm64Unknown => CpuFamily::Arm64,
265            Arch::Arm
266            | Arch::ArmV5
267            | Arch::ArmV6
268            | Arch::ArmV6m
269            | Arch::ArmV7
270            | Arch::ArmV7f
271            | Arch::ArmV7s
272            | Arch::ArmV7k
273            | Arch::ArmV7m
274            | Arch::ArmV7em
275            | Arch::ArmUnknown => CpuFamily::Arm32,
276            Arch::Ppc => CpuFamily::Ppc32,
277            Arch::Ppc64 => CpuFamily::Ppc64,
278            Arch::Mips => CpuFamily::Mips32,
279            Arch::Mips64 => CpuFamily::Mips64,
280            Arch::Arm64_32 | Arch::Arm64_32V8 | Arch::Arm64_32Unknown => CpuFamily::Arm64_32,
281            Arch::Wasm32 => CpuFamily::Wasm32,
282        }
283    }
284
285    /// Returns the canonical name of the CPU architecture.
286    ///
287    /// This follows the Apple conventions for naming architectures. For instance, Intel 32-bit
288    /// architectures are canonically named `"x86"`, even though `"i386"` would also be a valid
289    /// name.
290    ///
291    /// For architectures with variants or subtypes, that subtype is encoded into the name. For
292    /// instance the ARM v7-M architecture is named with a full `"armv7m".
293    ///
294    /// # Examples
295    ///
296    /// ```
297    /// use symbolic_common::Arch;
298    ///
299    /// // Will print "x86"
300    /// println!("{}", Arch::X86.name());
301    /// ```
302    pub fn name(self) -> &'static str {
303        match self {
304            Arch::Unknown => "unknown",
305            Arch::Wasm32 => "wasm32",
306            Arch::X86 => "x86",
307            Arch::X86Unknown => "x86_unknown",
308            Arch::Amd64 => "x86_64",
309            Arch::Amd64h => "x86_64h",
310            Arch::Amd64Unknown => "x86_64_unknown",
311            Arch::Arm64 => "arm64",
312            Arch::Arm64V8 => "arm64v8",
313            Arch::Arm64e => "arm64e",
314            Arch::Arm64Unknown => "arm64_unknown",
315            Arch::Arm => "arm",
316            Arch::ArmV5 => "armv5",
317            Arch::ArmV6 => "armv6",
318            Arch::ArmV6m => "armv6m",
319            Arch::ArmV7 => "armv7",
320            Arch::ArmV7f => "armv7f",
321            Arch::ArmV7s => "armv7s",
322            Arch::ArmV7k => "armv7k",
323            Arch::ArmV7m => "armv7m",
324            Arch::ArmV7em => "armv7em",
325            Arch::ArmUnknown => "arm_unknown",
326            Arch::Ppc => "ppc",
327            Arch::Ppc64 => "ppc64",
328            Arch::Mips => "mips",
329            Arch::Mips64 => "mips64",
330            Arch::Arm64_32 => "arm64_32",
331            Arch::Arm64_32V8 => "arm64_32_v8",
332            Arch::Arm64_32Unknown => "arm64_32_unknown",
333        }
334    }
335
336    /// Returns whether this architecture is well-known.
337    ///
338    /// This is trivially `true` for all architectures other than the `*Unknown` variants.
339    ///
340    /// # Examples
341    ///
342    /// ```
343    /// use symbolic_common::Arch;
344    ///
345    /// assert!(Arch::X86.well_known());
346    /// assert!(!Arch::X86Unknown.well_known());
347    /// ```
348    pub fn well_known(self) -> bool {
349        !matches!(
350            self,
351            Arch::Unknown
352                | Arch::ArmUnknown
353                | Arch::Arm64Unknown
354                | Arch::X86Unknown
355                | Arch::Amd64Unknown
356                | Arch::Arm64_32Unknown
357        )
358    }
359}
360
361impl fmt::Display for Arch {
362    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
363        write!(f, "{}", self.name())
364    }
365}
366
367impl str::FromStr for Arch {
368    type Err = UnknownArchError;
369
370    fn from_str(string: &str) -> Result<Arch, UnknownArchError> {
371        Ok(match string.to_ascii_lowercase().as_str() {
372            "unknown" => Arch::Unknown,
373            // this is an alias that is known among macho users
374            "i386" => Arch::X86,
375            "x86" => Arch::X86,
376            "x86_unknown" => Arch::X86Unknown,
377            "x86_64" | "amd64" => Arch::Amd64,
378            "x86_64h" => Arch::Amd64h,
379            "x86_64_unknown" => Arch::Amd64Unknown,
380            "arm64" => Arch::Arm64,
381            "arm64v8" => Arch::Arm64V8,
382            "arm64e" => Arch::Arm64e,
383            "arm64_unknown" => Arch::Arm64Unknown,
384            "arm" => Arch::Arm,
385            "armv5" => Arch::ArmV5,
386            "armv6" => Arch::ArmV6,
387            "armv6m" => Arch::ArmV6m,
388            "armv7" => Arch::ArmV7,
389            "armv7f" => Arch::ArmV7f,
390            "armv7s" => Arch::ArmV7s,
391            "armv7k" => Arch::ArmV7k,
392            "armv7m" => Arch::ArmV7m,
393            "armv7em" => Arch::ArmV7em,
394            "arm_unknown" => Arch::ArmUnknown,
395            "ppc" => Arch::Ppc,
396            "ppc64" => Arch::Ppc64,
397            "mips" => Arch::Mips,
398            "mips64" => Arch::Mips64,
399            "arm64_32" => Arch::Arm64_32,
400            "arm64_32_v8" => Arch::Arm64_32V8,
401            "arm64_32_unknown" => Arch::Arm64_32Unknown,
402
403            // apple crash report variants
404            "x86-64" => Arch::Amd64,
405            "arm-64" => Arch::Arm64,
406
407            // wasm extensions
408            "wasm32" => Arch::Wasm32,
409
410            _ => return Err(UnknownArchError),
411        })
412    }
413}
414
415/// An error returned for an invalid [`Language`](enum.Language.html).
416#[derive(Debug)]
417pub struct UnknownLanguageError;
418
419impl fmt::Display for UnknownLanguageError {
420    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
421        write!(f, "unknown language")
422    }
423}
424
425impl std::error::Error for UnknownLanguageError {}
426
427/// A programming language declared in debugging information.
428///
429/// In the context of function names or source code, the lanugage can help to determine appropriate
430/// strategies for demangling names or syntax highlighting. See the [`Name`] type, which declares a
431/// function name with an optional language.
432///
433/// This enumeration is represented as `u32` for C-bindings and lowlevel APIs.
434///
435/// [`Name`]: struct.Name.html
436#[repr(u32)]
437#[non_exhaustive]
438#[allow(missing_docs)]
439#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Default)]
440pub enum Language {
441    #[default]
442    Unknown = 0,
443    C = 1,
444    Cpp = 2,
445    D = 3,
446    Go = 4,
447    ObjC = 5,
448    ObjCpp = 6,
449    Rust = 7,
450    Swift = 8,
451    CSharp = 9,
452    VisualBasic = 10,
453    FSharp = 11,
454}
455
456impl Language {
457    /// Creates an `Language` from its `u32` representation.
458    ///
459    /// Returns `Language::Unknown` for all unknown values.
460    ///
461    /// # Examples
462    ///
463    /// ```
464    /// use symbolic_common::Language;
465    ///
466    /// // Will print "C"
467    /// println!("{:?}", Language::from_u32(1));
468    /// ```
469    pub fn from_u32(val: u32) -> Language {
470        match val {
471            0 => Self::Unknown,
472            1 => Self::C,
473            2 => Self::Cpp,
474            3 => Self::D,
475            4 => Self::Go,
476            5 => Self::ObjC,
477            6 => Self::ObjCpp,
478            7 => Self::Rust,
479            8 => Self::Swift,
480            9 => Self::CSharp,
481            10 => Self::VisualBasic,
482            11 => Self::FSharp,
483            _ => Self::Unknown,
484        }
485    }
486
487    /// Returns the name of the language.
488    ///
489    /// The name is always given in lower case without special characters or spaces, suitable for
490    /// serialization and parsing. For a human readable name, use the `Display` implementation,
491    /// instead.
492    ///
493    /// # Examples
494    ///
495    /// ```
496    /// use symbolic_common::Language;
497    ///
498    /// // Will print "objcpp"
499    /// println!("{}", Language::ObjCpp.name());
500    ///
501    /// // Will print "Objective-C++"
502    /// println!("{}", Language::ObjCpp);
503    /// ```
504    pub fn name(self) -> &'static str {
505        match self {
506            Language::Unknown => "unknown",
507            Language::C => "c",
508            Language::Cpp => "cpp",
509            Language::D => "d",
510            Language::Go => "go",
511            Language::ObjC => "objc",
512            Language::ObjCpp => "objcpp",
513            Language::Rust => "rust",
514            Language::Swift => "swift",
515            Language::CSharp => "csharp",
516            Language::VisualBasic => "visualbasic",
517            Language::FSharp => "fsharp",
518        }
519    }
520}
521
522impl fmt::Display for Language {
523    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
524        let formatted = match *self {
525            Language::Unknown => "unknown",
526            Language::C => "C",
527            Language::Cpp => "C++",
528            Language::D => "D",
529            Language::Go => "Go",
530            Language::ObjC => "Objective-C",
531            Language::ObjCpp => "Objective-C++",
532            Language::Rust => "Rust",
533            Language::Swift => "Swift",
534            Language::CSharp => "C#",
535            Language::VisualBasic => "Visual Basic",
536            Language::FSharp => "F#",
537        };
538
539        f.write_str(formatted)
540    }
541}
542
543impl str::FromStr for Language {
544    type Err = UnknownLanguageError;
545
546    fn from_str(string: &str) -> Result<Language, UnknownLanguageError> {
547        Ok(match string {
548            "unknown" => Language::Unknown,
549            "c" => Language::C,
550            "cpp" => Language::Cpp,
551            "d" => Language::D,
552            "go" => Language::Go,
553            "objc" => Language::ObjC,
554            "objcpp" => Language::ObjCpp,
555            "rust" => Language::Rust,
556            "swift" => Language::Swift,
557            "csharp" => Language::CSharp,
558            "visualbasic" => Language::VisualBasic,
559            "fsharp" => Language::FSharp,
560            _ => return Err(UnknownLanguageError),
561        })
562    }
563}
564
565/// A [`Name`]s mangling state.
566///
567/// By default, the mangling of a [`Name`] is not known, but an explicit mangling state can be set
568/// for Names that are guaranteed to be unmangled.
569#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
570#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Default)]
571pub enum NameMangling {
572    /// The [`Name`] is definitely mangled.
573    Mangled,
574    /// The [`Name`] is not mangled.
575    Unmangled,
576    /// The mangling of the [`Name`] is not known.
577    #[default]
578    Unknown,
579}
580
581/// The name of a potentially mangled symbol.
582///
583/// Debugging information often only contains mangled names in their symbol and debug information
584/// data. The mangling schema depends on the compiler and programming language. `Name` is a wrapper
585/// type for potentially mangled names and an optionally declared language. To demangle the name,
586/// see the `demangle` feature of `symbolic`.
587///
588/// Not all sources declare a programming language. In such a case, the [`language`] will be
589/// `Unknown`. However, it may still be inferred for demangling by inspecting the mangled string.
590///
591/// Names can refer either functions, types, fields, or virtual constructs. Their semantics are
592/// fully defined by the language and the compiler.
593///
594/// # Examples
595///
596/// Create a name and print it:
597///
598/// ```
599/// use symbolic_common::Name;
600///
601/// let name = Name::from("_ZN3foo3barEv");
602/// assert_eq!(name.to_string(), "_ZN3foo3barEv");
603/// ```
604///
605/// Create a name with a language and explicit mangling state.
606/// Alternate formatting prints the language:
607///
608/// ```
609/// use symbolic_common::{Language, Name, NameMangling};
610///
611/// let name = Name::new("_ZN3foo3barEv", NameMangling::Mangled, Language::Cpp);
612/// assert_eq!(format!("{:#}", name), "_ZN3foo3barEv [C++]");
613/// ```
614///
615/// [`language`]: struct.Name.html#method.language
616#[derive(Clone, Debug, Eq, Hash, PartialEq)]
617#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
618pub struct Name<'a> {
619    string: Cow<'a, str>,
620    lang: Language,
621    #[cfg_attr(feature = "serde", serde(default))]
622    mangling: NameMangling,
623}
624
625impl<'a> Name<'a> {
626    /// Constructs a new Name with given mangling and language.
627    ///
628    /// In case both the mangling state and the language are unknown, a simpler alternative to use
629    /// is [`Name::from`].
630    ///
631    ///
632    /// # Example
633    ///
634    /// ```
635    /// use symbolic_common::{Language, Name, NameMangling};
636    ///
637    /// let name = Name::new("_ZN3foo3barEv", NameMangling::Mangled, Language::Cpp);
638    /// assert_eq!(format!("{:#}", name), "_ZN3foo3barEv [C++]");
639    /// ```
640    #[inline]
641    pub fn new<S>(string: S, mangling: NameMangling, lang: Language) -> Self
642    where
643        S: Into<Cow<'a, str>>,
644    {
645        Name {
646            string: string.into(),
647            lang,
648            mangling,
649        }
650    }
651
652    /// Returns the raw, mangled string of the name.
653    ///
654    /// # Example
655    ///
656    /// ```
657    /// use symbolic_common::{Language, Name, NameMangling};
658    ///
659    /// let name = Name::new("_ZN3foo3barEv", NameMangling::Mangled, Language::Cpp);
660    /// assert_eq!(name.as_str(), "_ZN3foo3barEv");
661    /// ```
662    ///
663    /// This is also available as an `AsRef<str>` implementation:
664    ///
665    /// ```
666    /// use symbolic_common::{Language, Name, NameMangling};
667    ///
668    /// let name = Name::new("_ZN3foo3barEv", NameMangling::Mangled, Language::Cpp);
669    /// assert_eq!(name.as_ref(), "_ZN3foo3barEv");
670    /// ```
671    pub fn as_str(&self) -> &str {
672        &self.string
673    }
674
675    /// Set the `Name`'s language.
676    pub fn set_language(&mut self, language: Language) -> &mut Self {
677        self.lang = language;
678        self
679    }
680
681    /// The language of the mangled symbol.
682    ///
683    /// If the language is not declared in the source, this returns `Language::Unknown`. The
684    /// language may still be inferred using `detect_language`, which is declared on the `Demangle`
685    /// extension trait.
686    ///
687    /// # Example
688    ///
689    /// ```
690    /// use symbolic_common::{Language, Name, NameMangling};
691    ///
692    /// let name = Name::new("_ZN3foo3barEv", NameMangling::Mangled, Language::Cpp);
693    /// assert_eq!(name.language(), Language::Cpp);
694    /// ```
695    pub fn language(&self) -> Language {
696        self.lang
697    }
698
699    /// Set the `Name`'s mangling state.
700    pub fn set_mangling(&mut self, mangling: NameMangling) -> &mut Self {
701        self.mangling = mangling;
702        self
703    }
704
705    /// Returns the `Name`'s mangling state.
706    ///
707    /// # Example
708    ///
709    /// ```
710    /// use symbolic_common::{Language, Name, NameMangling};
711    ///
712    /// let unmangled = Name::new("foo::bar", NameMangling::Unmangled, Language::Unknown);
713    /// assert_eq!(unmangled.mangling(), NameMangling::Unmangled);
714    /// ```
715    pub fn mangling(&self) -> NameMangling {
716        self.mangling
717    }
718
719    /// Converts this name into a [`Cow`].
720    ///
721    /// # Example
722    ///
723    /// ```
724    /// use symbolic_common::Name;
725    ///
726    /// let name = Name::from("_ZN3foo3barEv");
727    /// assert_eq!(name.into_cow(), "_ZN3foo3barEv");
728    /// ```
729    pub fn into_cow(self) -> Cow<'a, str> {
730        self.string
731    }
732
733    /// Converts this name into a [`String`].
734    ///
735    /// # Example
736    ///
737    /// ```
738    /// use symbolic_common::Name;
739    ///
740    /// let name = Name::from("_ZN3foo3barEv");
741    /// assert_eq!(name.into_string(), "_ZN3foo3barEv");
742    /// ```
743    pub fn into_string(self) -> String {
744        self.string.into_owned()
745    }
746}
747
748impl AsRef<str> for Name<'_> {
749    fn as_ref(&self) -> &str {
750        self.as_str()
751    }
752}
753
754impl From<Name<'_>> for String {
755    fn from(name: Name) -> Self {
756        name.string.into()
757    }
758}
759
760impl<'a, S> From<S> for Name<'a>
761where
762    S: Into<Cow<'a, str>>,
763{
764    fn from(string: S) -> Self {
765        Self::new(string, NameMangling::Unknown, Language::Unknown)
766    }
767}
768
769impl fmt::Display for Name<'_> {
770    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
771        write!(f, "{}", self.as_str())?;
772
773        if f.alternate() && self.lang != Language::Unknown {
774            write!(f, " [{}]", self.lang)?;
775        }
776
777        Ok(())
778    }
779}
780
781macro_rules! impl_eq {
782    ($lhs:ty, $rhs: ty) => {
783        #[allow(clippy::extra_unused_lifetimes)]
784        impl<'a, 'b> PartialEq<$rhs> for $lhs {
785            #[inline]
786            fn eq(&self, other: &$rhs) -> bool {
787                PartialEq::eq(&self.string, other)
788            }
789        }
790
791        #[allow(clippy::extra_unused_lifetimes)]
792        impl<'a, 'b> PartialEq<$lhs> for $rhs {
793            #[inline]
794            fn eq(&self, other: &$lhs) -> bool {
795                PartialEq::eq(self, &other.string)
796            }
797        }
798    };
799}
800
801impl_eq! { Name<'a>, str }
802impl_eq! { Name<'a>, &'b str }
803impl_eq! { Name<'a>, String }
804impl_eq! { Name<'a>, std::borrow::Cow<'b, str> }
805
806#[cfg(feature = "serde")]
807mod derive_serde {
808    /// Helper macro to implement string based serialization and deserialization.
809    ///
810    /// If a type implements `FromStr` and `Display` then this automatically
811    /// implements a serializer/deserializer for that type that dispatches
812    /// appropriately.
813    macro_rules! impl_str_serde {
814        ($type:ty) => {
815            impl ::serde::ser::Serialize for $type {
816                fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
817                where
818                    S: ::serde::ser::Serializer,
819                {
820                    serializer.serialize_str(self.name())
821                }
822            }
823
824            impl<'de> ::serde::de::Deserialize<'de> for $type {
825                fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
826                where
827                    D: ::serde::de::Deserializer<'de>,
828                {
829                    <::std::borrow::Cow<str>>::deserialize(deserializer)?
830                        .parse()
831                        .map_err(::serde::de::Error::custom)
832                }
833            }
834        };
835    }
836
837    impl_str_serde!(super::Arch);
838    impl_str_serde!(super::Language);
839}