bitcoin_internals/
parse.rs

1/// Support for parsing strings.
2
3// Impls a single TryFrom conversion
4#[doc(hidden)]
5#[macro_export]
6macro_rules! impl_try_from_stringly {
7    ($from:ty, $to:ty, $error:ty, $func:expr) => {
8        $(#[$attr])?
9        impl core::convert::TryFrom<$from> for $to {
10            type Error = $error;
11
12            fn try_from(s: $from) -> core::result::Result<Self, Self::Error> {
13                $func(AsRef::<str>::as_ref(s)).map_err(|source| <$error>::new(s, source))
14            }
15        }
16
17    }
18}
19
20/// Implements conversions from various string types.
21///
22/// This macro implements `FromStr` as well as `TryFrom<{stringly}` where `{stringly}` is one of
23/// these types:
24///
25/// * `&str`
26/// * `String`
27/// * `Box<str>`
28/// * `Cow<'_, str>`
29///
30/// The last three are only available with `alloc` feature turned on.
31#[macro_export]
32macro_rules! impl_parse {
33    ($type:ty, $descr:expr, $func:expr, $vis:vis $error:ident, $error_source:ty $(, $error_derive:path)*) => {
34        $crate::parse_error_type!($vis $error, $error_source, $descr $(, $error_derive)*);
35
36        impl core::str::FromStr for $type {
37            type Err = $error;
38
39            fn from_str(s: &str) -> core::result::Result<Self, Self::Err> {
40                $func(s).map_err(|source| <$error>::new(s, source))
41            }
42        }
43
44        impl_try_from_stringly!(&str);
45
46        #[cfg(feature = "alloc")]
47        impl_try_from_stringly!(alloc::string::String, $type, $error, $func);
48        #[cfg(feature = "alloc")]
49        impl_try_from_stringly!(alloc::borrow::Cow<'_, str>, $type, $error, $func);
50        #[cfg(feature = "alloc")]
51        impl_try_from_stringly!(alloc::boxed::Box<str>, $type, $error, $func);
52    }
53}
54
55/// Implements conversions from various string types as well as `serde` (de)serialization.
56///
57/// This calls `impl_parse` macro and implements serde deserialization by expecting and parsing a
58/// string and serialization by outputting a string.
59#[macro_export]
60macro_rules! impl_parse_and_serde {
61    ($type:ty, $descr:expr, $func:expr, $error:ident, $error_source:ty $(, $error_derive:path)*) => {
62        impl_parse!($type, $descr, $func, $error, $error_source $(, $error_derive)*);
63
64        // We don't use `serde_string_impl` because we want to avoid allocating input.
65        #[cfg(feature = "serde")]
66        impl<'de> $crate::serde::Deserialize<'de> for $type {
67            fn deserialize<D>(deserializer: D) -> core::result::Result<$name, D::Error>
68            where
69                D: $crate::serde::de::Deserializer<'de>,
70            {
71                use core::fmt::{self, Formatter};
72                use core::str::FromStr;
73
74                struct Visitor;
75                impl<'de> $crate::serde::de::Visitor<'de> for Visitor {
76                    type Value = $name;
77
78                    fn expecting(&self, f: &mut Formatter) -> core::fmt::Result {
79                        f.write_str($descr)
80                    }
81
82                    fn visit_str<E>(self, s: &str) -> core::result::Result<Self::Value, E>
83                    where
84                        E: $crate::serde::de::Error,
85                    {
86                        s.parse().map_err(|error| {
87                            $crate::serde::IntoDeError::try_into_de_error(error)
88                                .unwrap_or_else(|_| E::invalid_value(Unexpected::Str(s), &self))
89                        })
90                    }
91                }
92
93                deserializer.deserialize_str(Visitor)
94            }
95        }
96
97        #[cfg(feature = "serde")]
98        impl $crate::serde::Serialize for $name {
99            fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error>
100            where
101                S: $crate::serde::Serializer,
102            {
103                serializer.collect_str(&self)
104            }
105        }
106    }
107}