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}