108 lines
3.7 KiB
Rust
108 lines
3.7 KiB
Rust
/// Support for parsing strings.
|
|
|
|
// Impls a single TryFrom conversion
|
|
#[doc(hidden)]
|
|
#[macro_export]
|
|
macro_rules! impl_try_from_stringly {
|
|
($from:ty, $to:ty, $error:ty, $func:expr) => {
|
|
$(#[$attr])?
|
|
impl core::convert::TryFrom<$from> for $to {
|
|
type Error = $error;
|
|
|
|
fn try_from(s: $from) -> core::result::Result<Self, Self::Error> {
|
|
$func(AsRef::<str>::as_ref(s)).map_err(|source| <$error>::new(s, source))
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
/// Implements conversions from various string types.
|
|
///
|
|
/// This macro implements `FromStr` as well as `TryFrom<{stringly}` where `{stringly}` is one of
|
|
/// these types:
|
|
///
|
|
/// * `&str`
|
|
/// * `String`
|
|
/// * `Box<str>`
|
|
/// * `Cow<'_, str>`
|
|
///
|
|
/// The last three are only available with `alloc` feature turned on.
|
|
#[macro_export]
|
|
macro_rules! impl_parse {
|
|
($type:ty, $descr:expr, $func:expr, $vis:vis $error:ident, $error_source:ty $(, $error_derive:path)*) => {
|
|
$crate::parse_error_type!($vis $error, $error_source, $descr $(, $error_derive)*);
|
|
|
|
impl core::str::FromStr for $type {
|
|
type Err = $error;
|
|
|
|
fn from_str(s: &str) -> core::result::Result<Self, Self::Err> {
|
|
$func(s).map_err(|source| <$error>::new(s, source))
|
|
}
|
|
}
|
|
|
|
impl_try_from_stringly!(&str);
|
|
|
|
#[cfg(feature = "alloc")]
|
|
impl_try_from_stringly!(alloc::string::String, $type, $error, $func);
|
|
#[cfg(feature = "alloc")]
|
|
impl_try_from_stringly!(alloc::borrow::Cow<'_, str>, $type, $error, $func);
|
|
#[cfg(feature = "alloc")]
|
|
impl_try_from_stringly!(alloc::boxed::Box<str>, $type, $error, $func);
|
|
}
|
|
}
|
|
|
|
/// Implements conversions from various string types as well as `serde` (de)serialization.
|
|
///
|
|
/// This calls `impl_parse` macro and implements serde deserialization by expecting and parsing a
|
|
/// string and serialization by outputting a string.
|
|
#[macro_export]
|
|
macro_rules! impl_parse_and_serde {
|
|
($type:ty, $descr:expr, $func:expr, $error:ident, $error_source:ty $(, $error_derive:path)*) => {
|
|
impl_parse!($type, $descr, $func, $error, $error_source $(, $error_derive)*);
|
|
|
|
// We don't use `serde_string_impl` because we want to avoid allocating input.
|
|
#[cfg(feature = "serde")]
|
|
impl<'de> $crate::serde::Deserialize<'de> for $type {
|
|
fn deserialize<D>(deserializer: D) -> core::result::Result<$name, D::Error>
|
|
where
|
|
D: $crate::serde::de::Deserializer<'de>,
|
|
{
|
|
use core::fmt::{self, Formatter};
|
|
use core::str::FromStr;
|
|
|
|
struct Visitor;
|
|
impl<'de> $crate::serde::de::Visitor<'de> for Visitor {
|
|
type Value = $name;
|
|
|
|
fn expecting(&self, f: &mut Formatter) -> core::fmt::Result {
|
|
f.write_str($descr)
|
|
}
|
|
|
|
fn visit_str<E>(self, s: &str) -> core::result::Result<Self::Value, E>
|
|
where
|
|
E: $crate::serde::de::Error,
|
|
{
|
|
s.parse().map_err(|error| {
|
|
$crate::serde::IntoDeError::try_into_de_error(error)
|
|
.unwrap_or_else(|_| E::invalid_value(Unexpected::Str(s), &self))
|
|
})
|
|
}
|
|
}
|
|
|
|
deserializer.deserialize_str(Visitor)
|
|
}
|
|
}
|
|
|
|
#[cfg(feature = "serde")]
|
|
impl $crate::serde::Serialize for $name {
|
|
fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error>
|
|
where
|
|
S: $crate::serde::Serializer,
|
|
{
|
|
serializer.collect_str(&self)
|
|
}
|
|
}
|
|
}
|
|
}
|