prse/lending_parse.rs
1use core::num::*;
2use core::str::FromStr;
3
4use crate::parse_error::ParseError;
5
6/// Parse a string into the implemented type, unlike [`FromStr`] this trait allows
7/// you to borrow the string. It can be automatically derived using
8/// [`Parse`](prse_derive::Parse).
9pub trait Parse<'a> {
10 /// Parses a string `s` to a return value of this type.
11 ///
12 /// If parsing succeeds, return the value inside [`Ok`], otherwise
13 /// when the string is ill-formatted return a [`ParseError`].
14 ///
15 /// ```
16 /// # use prse::{parse, Parse, ParseError};
17 /// # #[derive(PartialEq, Debug)]
18 /// struct Count<'b>(&'b str, u32);
19 ///
20 /// impl<'a> Parse<'a> for Count<'a> {
21 /// fn from_str(s: &'a str) -> Result<Self, ParseError> {
22 /// let (fruit, count) = s.split_once(':').ok_or_else(|| ParseError::new("expected a colon."))?;
23 /// Ok(Count(<&'a str>::from_str(fruit)?, <u32>::from_str(count.trim())?))
24 /// }
25 /// }
26 ///
27 /// let c: Count = parse!("I have: {apple: 8}.", "I have: {{{}}}.");
28 /// assert_eq!(c, Count("apple", 8));
29 /// ```
30 ///
31 /// It also allows you to add your own custom parsing function.
32 ///
33 /// ```
34 /// # use prse::{parse, Parse, ParseError};
35 /// # #[derive(PartialEq, Debug)]
36 /// struct Hex(i32);
37 ///
38 /// impl<'a> Parse<'a> for Hex {
39 /// fn from_str(s: &'a str) -> Result<Self, ParseError> {
40 /// Ok(Hex(i32::from_str_radix(s, 16)?)) // Using 16 for Hexadecimal numbers
41 /// }
42 /// }
43 ///
44 /// let v: Hex = parse!("A", "{}");
45 /// assert_eq!(v, Hex(10));
46 /// ```
47 fn from_str(s: &'a str) -> Result<Self, ParseError>
48 where
49 Self: Sized;
50}
51
52impl<'a> Parse<'a> for &'a str {
53 fn from_str(s: &'a str) -> Result<Self, ParseError> {
54 Ok(s)
55 }
56}
57
58macro_rules! impl_parse {
59 ( $( $Ty: ty )+) => {
60 $(
61 impl<'a> Parse<'a> for $Ty {
62 fn from_str(s: &'a str) -> Result<Self, ParseError> {
63 <Self as FromStr>::from_str(s.trim()).map_err(|e| e.into())
64 }
65 }
66 )+
67 };
68}
69
70#[cfg(feature = "alloc")]
71macro_rules! impl_parse_infallible {
72 ( $( $Ty: ty )+) => {
73 $(
74 impl<'a> Parse<'a> for $Ty {
75 fn from_str(s: &'a str) -> Result<Self, ParseError> {
76 Ok(<Self as FromStr>::from_str(&s).unwrap())
77 }
78 }
79 )+
80 };
81}
82
83impl_parse!(isize i8 i16 i32 i64 i128 usize u8 u16 u32 u64 u128);
84impl_parse!(bool char f32 f64);
85impl_parse!(NonZeroU8 NonZeroU16 NonZeroU32 NonZeroU64 NonZeroU128 NonZeroUsize);
86impl_parse!(NonZeroI8 NonZeroI16 NonZeroI32 NonZeroI64 NonZeroI128 NonZeroIsize);
87
88#[cfg(feature = "alloc")]
89mod impl_alloc {
90 extern crate alloc;
91
92 use alloc::string::String;
93
94 use super::{FromStr, Parse, ParseError};
95
96 impl_parse_infallible!(String);
97}
98
99#[cfg(feature = "std")]
100mod impl_std {
101 use std::ffi::OsString;
102 use std::net::*;
103 use std::path::PathBuf;
104
105 use super::{FromStr, Parse, ParseError};
106
107 impl_parse_infallible!(OsString PathBuf);
108 impl_parse!(IpAddr SocketAddr Ipv4Addr Ipv6Addr SocketAddrV4 SocketAddrV6);
109}
110
111/// An str extension trait to allow you to call the `from_str` from [`Parse`]
112/// without specifying the type.
113///
114/// The trait is sealed and cannot be implemented on any other type.
115pub trait ExtParseStr: __private::Sealed {
116 /// Parses the string slice into another type.
117 ///
118 /// lending_parse can parse into any type that implements the [`Parse`] trait.
119 fn lending_parse<'a, F: Parse<'a>>(&'a self) -> Result<F, ParseError>;
120}
121
122impl ExtParseStr for str {
123 fn lending_parse<'a, F: Parse<'a>>(&'a self) -> Result<F, ParseError> {
124 Parse::from_str(self)
125 }
126}
127
128#[doc(hidden)]
129mod __private {
130 pub trait Sealed {}
131
132 impl Sealed for str {}
133}