Skip to main content

pistonite_cu/parse/
base.rs

1/// The parsing utilities in `cu` provides wrapper to the std library
2/// for parsing common data, such as different radix for numbers,
3/// and support for common formats like `json`, `yaml` and `toml`.
4///
5/// Everything only works with UTF-8.
6///
7/// The entry points to parsing are [`cu::parse::<T>`](crate::parse), and `"...".parse_to::<T>()`.
8/// Use whichever is more readable or preferrable at the call sites.
9///
10/// ```rust
11/// # use pistonite_cu as cu;
12/// use std::path::PathBuf;
13/// use cu::pre::*;
14///
15/// # fn main() -> cu::Result<()> {
16/// # use pistonite_cu as cu;
17/// // bool: empty string, 0, 1, "true", or "false", case-insensitive
18/// let x = cu::parse::<bool>("0")?;
19/// assert_eq!(x, false);
20///
21/// // numbers: hex, oct and binary are supported with 0x, 0b, and 0o prefix
22/// let x = cu::parse::<u32>("0")?;
23/// assert_eq!(x, 0);
24/// let x = cu::parse::<i32>("-123")?;
25/// assert_eq!(x, -123);
26/// let x = cu::parse::<usize>("0x123")?;
27/// assert_eq!(x, 0x123);
28///
29/// // .parse_to() can be used when chaining,
30/// // instead of wrapping in cu::parse or use a temporary variable.
31/// let _x = "imagine some long chaining is used to get this value"
32///     .parse_to::<PathBuf>()?;
33/// # Ok(()) }
34/// ```
35///
36/// If the value is owned, you can use `parse_owned` instead of `parse`.
37/// For readers, use [`cu::read`] or [`cu::co_read`] for async readers.
38///
39/// # From Owned and Read
40/// When possible, implementation of parsing from a `io::Read` is provided
41/// for optimization (for example for `json` inputs using `serde_json::from_reader`).
42///
43/// Async read is also supported, however, at the time of writing,
44/// the inputs are first read into a buffer asynchronously, then
45/// parsed synchronously from the buffer.
46///
47/// # Remote Derive
48/// Common types are implemented in this library. You can derive
49/// this trait by using the [`Parse`] derive macro
50/// for any type that implements [`FromStr`].
51///
52/// # Common Formats
53/// When `json`/`yaml`/`toml` features are enabled, the respective
54/// module will be included in the prelude.
55/// See [`json`]/[`yaml`]/[`toml`] for more details.
56///
57/// [`FromStr`]: std::str::FromStr
58/// [`Parse`]: macro@crate::Parse
59/// [`json`]: module@crate::json
60/// [`yaml`]: module@crate::yaml
61/// [`toml`]: module@crate::toml
62/// [`cu::read`]: crate::read
63/// [`cu::co_read`]: crate::co_read
64pub trait Parse
65where
66    Self: Sized,
67{
68    type Output;
69    fn parse_borrowed(x: &str) -> crate::Result<Self::Output>;
70    fn parse_owned(x: String) -> crate::Result<Self::Output> {
71        Self::parse_borrowed(&x)
72    }
73    fn parse_read(mut x: impl std::io::Read) -> crate::Result<Self::Output> {
74        use crate::Context as _;
75        let mut s = String::new();
76        x.read_to_string(&mut s).context("io error while parsing")?;
77        Self::parse_owned(s)
78    }
79}
80
81/// the `.parse_to` function.
82///
83/// See [`Parse`](trait@Parse)
84pub trait ParseTo {
85    fn parse_to<T: Parse>(self) -> crate::Result<T::Output>;
86}
87impl ParseTo for &str {
88    fn parse_to<T: Parse>(self) -> crate::Result<T::Output> {
89        T::parse_borrowed(self)
90    }
91}
92impl ParseTo for &mut str {
93    fn parse_to<T: Parse>(self) -> crate::Result<T::Output> {
94        T::parse_borrowed(self)
95    }
96}
97impl ParseTo for String {
98    fn parse_to<T: Parse>(self) -> crate::Result<T::Output> {
99        T::parse_owned(self)
100    }
101}
102
103/// Parse a value from a `&str`.
104///
105/// See [`Parse`](trait@Parse)
106#[inline(always)]
107pub fn parse<T: Parse>(x: &str) -> crate::Result<T::Output> {
108    T::parse_borrowed(x)
109}
110
111/// Parse a value from a `String`.
112///
113/// See [`Parse`](trait@Parse)
114#[inline(always)]
115pub fn parse_owned<T: Parse>(x: String) -> crate::Result<T::Output> {
116    T::parse_owned(x)
117}
118
119/// Parse a value from a `std::io::Read`.
120///
121/// See [`Parse`](trait@Parse)
122#[inline(always)]
123pub fn read<T: Parse>(x: impl std::io::Read) -> crate::Result<T::Output> {
124    T::parse_read(x)
125}
126
127/// Parse a value from a `tokio::io::AsyncRead`.
128///
129/// See [`Parse`](trait@Parse)
130#[cfg(feature = "coroutine")]
131pub async fn co_read<T: Parse>(
132    mut x: impl tokio::io::AsyncRead + Unpin,
133) -> crate::Result<T::Output> {
134    use crate::Context as _;
135    use tokio::io::AsyncReadExt as _;
136    let mut s = String::new();
137    x.read_to_string(&mut s)
138        .await
139        .context("io error while parsing")?;
140    T::parse_owned(s)
141}