.
This commit is contained in:
commit
7d58a94d5a
11 changed files with 585 additions and 0 deletions
3
.vim/coc-settings.json
Normal file
3
.vim/coc-settings.json
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"rust-analyzer.cargo.features": "all"
|
||||||
|
}
|
28
Cargo.toml
Normal file
28
Cargo.toml
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
[package]
|
||||||
|
name = "estring"
|
||||||
|
description = "A simple way to parse a string using type annotations"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2018"
|
||||||
|
authors = ["Dmitriy Pleshevskiy <dmitriy@ideascup.me>"]
|
||||||
|
readme = "README.md"
|
||||||
|
repository = "https://github.com/pleshevskiy/itconfig-rs/tree/redesign/estring"
|
||||||
|
license = "MIT"
|
||||||
|
keywords = ["parsing", "type", "annotations", "customizable"]
|
||||||
|
categories = ["data-structures", "parsing"]
|
||||||
|
|
||||||
|
# rust-version = "1.51.0" # The first version of Cargo that supports this field is 1.56.0
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
msrv = "1.51.0"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[features]
|
||||||
|
number = []
|
||||||
|
bool = []
|
||||||
|
vec = []
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
|
||||||
|
[badges]
|
||||||
|
maintenance = { status = "actively-developed" }
|
21
LICENSE
Normal file
21
LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2022 pleshevskiy
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
57
README.md
Normal file
57
README.md
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
# EString
|
||||||
|
|
||||||
|
A simple way to parse a string using type annotations.
|
||||||
|
|
||||||
|
This package was originally designed for [enve]
|
||||||
|
|
||||||
|
[enve]: https://github.com/pleshevskiy/itconfig-rs/tree/redesign
|
||||||
|
|
||||||
|
## Getting started
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use estring::{SepVec, EString};
|
||||||
|
|
||||||
|
type PlusVec<T> = SepVec<T, '+'>;
|
||||||
|
type MulVec<T> = SepVec<T, '*'>;
|
||||||
|
|
||||||
|
fn main() -> Result<(), estring::ParseError> {
|
||||||
|
let res = EString::from("10+5*2+3")
|
||||||
|
.parse::<PlusVec<MulVec<f32>>>()?
|
||||||
|
.iter()
|
||||||
|
.map(|m| m.iter().product::<f32>())
|
||||||
|
.sum::<f32>();
|
||||||
|
|
||||||
|
assert_eq!(res, 23.0);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
You can use custom types as annotations! Just implement `TryFrom<EString>`!
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
**The MSRV is 1.51.0**
|
||||||
|
|
||||||
|
Add `estring = { version = "0.1", features = ["vec", "number"] }` as a
|
||||||
|
dependency in `Cargo.toml`.
|
||||||
|
|
||||||
|
`Cargo.toml` example:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[package]
|
||||||
|
name = "my-crate"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Me <user@rust-lang.org>"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
estring = { version = "0.1", features = ["vec", "number"] }
|
||||||
|
```
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
**MIT**. See [LICENSE](./LICENSE) to see the full text.
|
||||||
|
|
||||||
|
## Contributors
|
||||||
|
|
||||||
|
[pleshevskiy](https://github.com/pleshevskiy) (Dmitriy Pleshevskiy) – creator,
|
||||||
|
maintainer.
|
99
src/core.rs
Normal file
99
src/core.rs
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
//! Contains the ``EString`` type, as well as the basic implementation of conversions to
|
||||||
|
//! string types
|
||||||
|
//!
|
||||||
|
#[cfg(any(feature = "number", feature = "bool"))]
|
||||||
|
pub mod prim;
|
||||||
|
#[cfg(any(feature = "number", feature = "bool"))]
|
||||||
|
pub use prim::*;
|
||||||
|
|
||||||
|
#[cfg(feature = "vec")]
|
||||||
|
pub mod vec;
|
||||||
|
#[cfg(feature = "vec")]
|
||||||
|
pub use vec::*;
|
||||||
|
|
||||||
|
use crate::ParseError;
|
||||||
|
use std::convert::{Infallible, TryFrom};
|
||||||
|
|
||||||
|
/// Wrapper under String type.
|
||||||
|
#[derive(Debug, Default, PartialEq, Eq, Clone)]
|
||||||
|
pub struct EString(pub String);
|
||||||
|
|
||||||
|
impl EString {
|
||||||
|
/// Parses inner string by type annotations and returns result.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// Will return `Err` if estring cannot parse inner fragment
|
||||||
|
///
|
||||||
|
#[inline]
|
||||||
|
pub fn parse<T: TryFrom<EString>>(self) -> Result<T, ParseError> {
|
||||||
|
let orig = self.0.clone();
|
||||||
|
<T as TryFrom<EString>>::try_from(self).map_err(|_| ParseError(orig))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> From<T> for EString
|
||||||
|
where
|
||||||
|
T: std::fmt::Display,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn from(val: T) -> Self {
|
||||||
|
Self(val.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::Deref for EString {
|
||||||
|
type Target = String;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<EString> for String {
|
||||||
|
type Error = Infallible;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn try_from(s: EString) -> Result<Self, Self::Error> {
|
||||||
|
Ok(s.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<EString> for &'static str {
|
||||||
|
type Error = Infallible;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn try_from(s: EString) -> Result<Self, Self::Error> {
|
||||||
|
Ok(Box::leak(s.0.into_boxed_str()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_deref_to_string() {
|
||||||
|
let estr = EString::from("hello");
|
||||||
|
assert_eq!(*estr, String::from("hello"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_parse_into_itself() {
|
||||||
|
let estr = EString::from("hello");
|
||||||
|
match estr.parse::<EString>() {
|
||||||
|
Ok(res) => assert_eq!(res, EString::from("hello")),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_parse_into_string() {
|
||||||
|
let estr = EString::from("hello");
|
||||||
|
match estr.parse::<String>() {
|
||||||
|
Ok(res) => assert_eq!(res, String::from("hello")),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
14
src/core/prim.rs
Normal file
14
src/core/prim.rs
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
//! Contains the implementations to primitive types (number, boolean)
|
||||||
|
//!
|
||||||
|
//! **NOTE**: Require the enabling of the same-name features
|
||||||
|
//!
|
||||||
|
|
||||||
|
#[cfg(feature = "bool")]
|
||||||
|
mod bool;
|
||||||
|
#[cfg(feature = "bool")]
|
||||||
|
pub use self::bool::*;
|
||||||
|
|
||||||
|
#[cfg(feature = "number")]
|
||||||
|
mod number;
|
||||||
|
#[cfg(feature = "number")]
|
||||||
|
pub use self::number::*;
|
57
src/core/prim/bool.rs
Normal file
57
src/core/prim/bool.rs
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
use crate::core::EString;
|
||||||
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
|
impl TryFrom<EString> for bool {
|
||||||
|
type Error = ();
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn try_from(s: EString) -> Result<Self, Self::Error> {
|
||||||
|
match s.to_lowercase().as_str() {
|
||||||
|
"true" | "t" | "yes" | "y" | "on" | "1" => Ok(true),
|
||||||
|
"false" | "f" | "no" | "n" | "off" | "0" | "" => Ok(false),
|
||||||
|
_ => Err(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::ParseError;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_parse_bool_variable() {
|
||||||
|
let test_cases = [
|
||||||
|
("1", true),
|
||||||
|
("0", false),
|
||||||
|
("y", true),
|
||||||
|
("f", false),
|
||||||
|
("yes", true),
|
||||||
|
("true", true),
|
||||||
|
("false", false),
|
||||||
|
("t", true),
|
||||||
|
("f", false),
|
||||||
|
("on", true),
|
||||||
|
("off", false),
|
||||||
|
];
|
||||||
|
|
||||||
|
for (val, expected) in test_cases {
|
||||||
|
let estr = EString::from(val);
|
||||||
|
match estr.parse::<bool>() {
|
||||||
|
Ok(res) => assert_eq!(res, expected),
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_throw_parse_error() {
|
||||||
|
let estr = EString::from("something");
|
||||||
|
match estr.parse::<bool>() {
|
||||||
|
Err(ParseError(orig)) => {
|
||||||
|
assert_eq!(orig, String::from("something"));
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
62
src/core/prim/number.rs
Normal file
62
src/core/prim/number.rs
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
use crate::core::EString;
|
||||||
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
macro_rules! from_env_string_numbers_impl {
|
||||||
|
($($ty:ty),+$(,)?) => {
|
||||||
|
$(
|
||||||
|
#[cfg(feature = "number")]
|
||||||
|
impl TryFrom<EString> for $ty {
|
||||||
|
type Error = <$ty as std::str::FromStr>::Err;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn try_from(s: EString) -> Result<Self, Self::Error> {
|
||||||
|
s.0.parse::<Self>()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)+
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
|
from_env_string_numbers_impl![
|
||||||
|
i8, i16, i32, i64, i128, isize,
|
||||||
|
u8, u16, u32, u64, u128, usize,
|
||||||
|
f32, f64
|
||||||
|
];
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::ParseError;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_parse_number() {
|
||||||
|
let estr = EString::from("-10");
|
||||||
|
match estr.parse::<i32>() {
|
||||||
|
Ok(res) => assert_eq!(res, -10),
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_parse_float_number() {
|
||||||
|
let estr = EString::from("-0.15");
|
||||||
|
match estr.parse::<f32>() {
|
||||||
|
#[allow(clippy::float_cmp)]
|
||||||
|
Ok(res) => assert_eq!(res, -0.15),
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_throw_parse_error() {
|
||||||
|
let estr = EString::from("-10");
|
||||||
|
match estr.parse::<u32>() {
|
||||||
|
Err(ParseError(orig)) => {
|
||||||
|
assert_eq!(orig, String::from("-10"));
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
153
src/core/vec.rs
Normal file
153
src/core/vec.rs
Normal file
|
@ -0,0 +1,153 @@
|
||||||
|
//! Contains the implementations to vec type
|
||||||
|
//!
|
||||||
|
//! **NOTE**: Require the enabling of the `vec` features
|
||||||
|
//!
|
||||||
|
|
||||||
|
use crate::core::EString;
|
||||||
|
use std::convert::TryFrom;
|
||||||
|
use std::fmt::Write;
|
||||||
|
|
||||||
|
/// Wrapper for ``Vec`` to split string by a separator (`SEP`).
|
||||||
|
///
|
||||||
|
/// **NOTE**: Required the enabling of the `vec` feature.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use estring::{SepVec, EString};
|
||||||
|
///
|
||||||
|
/// type CommaVec<T> = SepVec<T, ','>;
|
||||||
|
///
|
||||||
|
/// fn main() -> Result<(), estring::ParseError> {
|
||||||
|
/// let res = EString::from("1,2,3").parse::<CommaVec<u8>>()?;
|
||||||
|
/// assert_eq!(*res, vec![1, 2, 3]);
|
||||||
|
///
|
||||||
|
/// Ok(())
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
|
pub struct SepVec<T, const SEP: char>(pub Vec<T>);
|
||||||
|
|
||||||
|
impl<T, const SEP: char> std::ops::Deref for SepVec<T, SEP> {
|
||||||
|
type Target = Vec<T>;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, const SEP: char> From<Vec<T>> for SepVec<T, SEP> {
|
||||||
|
#[inline]
|
||||||
|
fn from(vec: Vec<T>) -> Self {
|
||||||
|
Self(vec)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, const SEP: char> std::fmt::Display for SepVec<T, SEP>
|
||||||
|
where
|
||||||
|
T: std::fmt::Display,
|
||||||
|
{
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
self.0.iter().enumerate().try_for_each(|(i, part)| {
|
||||||
|
if i != 0 {
|
||||||
|
f.write_char(SEP)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
f.write_str(&part.to_string())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, const SEP: char> TryFrom<EString> for SepVec<T, SEP>
|
||||||
|
where
|
||||||
|
T: TryFrom<EString> + std::fmt::Display,
|
||||||
|
{
|
||||||
|
type Error = T::Error;
|
||||||
|
|
||||||
|
fn try_from(value: EString) -> Result<Self, Self::Error> {
|
||||||
|
let inner = value
|
||||||
|
.split(SEP)
|
||||||
|
.map(str::trim)
|
||||||
|
.map(EString::from)
|
||||||
|
.map(T::try_from)
|
||||||
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
Ok(Self(inner))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
const COMMA: char = ',';
|
||||||
|
const SEMI: char = ';';
|
||||||
|
|
||||||
|
type CommaVec<T> = SepVec<T, COMMA>;
|
||||||
|
type SemiVec<T> = SepVec<T, SEMI>;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_parse_into_vec() {
|
||||||
|
let estr = EString::from("a,b,c,d,e");
|
||||||
|
match estr.parse::<CommaVec<&str>>() {
|
||||||
|
Ok(res) => assert_eq!(*res, vec!["a", "b", "c", "d", "e"]),
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_trim_identations_before_parsing() {
|
||||||
|
let input = "
|
||||||
|
a , b, c,
|
||||||
|
d,e";
|
||||||
|
let estr = EString::from(input);
|
||||||
|
match estr.parse::<CommaVec<&str>>() {
|
||||||
|
Ok(res) => assert_eq!(*res, vec!["a", "b", "c", "d", "e"]),
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_parse_into_vector_of_vectors() {
|
||||||
|
let estr = EString::from("a,b; c,d,e; f,g");
|
||||||
|
match estr.parse::<SemiVec<CommaVec<&str>>>() {
|
||||||
|
Ok(res) => assert_eq!(
|
||||||
|
res,
|
||||||
|
SemiVec::from(vec![
|
||||||
|
CommaVec::from(vec!["a", "b"]),
|
||||||
|
CommaVec::from(vec!["c", "d", "e"]),
|
||||||
|
CommaVec::from(vec!["f", "g"])
|
||||||
|
])
|
||||||
|
),
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "number")]
|
||||||
|
mod numbers {
|
||||||
|
use super::*;
|
||||||
|
use crate::ParseError;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_parse_into_num_vec() {
|
||||||
|
let estr = EString::from("1,2,3,4,5");
|
||||||
|
match estr.parse::<CommaVec<i32>>() {
|
||||||
|
Ok(res) => assert_eq!(*res, vec![1, 2, 3, 4, 5]),
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_throw_parse_vec_error() {
|
||||||
|
let estr = EString::from("1,2,3,4,5");
|
||||||
|
match estr.parse::<SemiVec<i32>>() {
|
||||||
|
Err(ParseError(orig)) => {
|
||||||
|
assert_eq!(orig, String::from("1,2,3,4,5"));
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
19
src/error.rs
Normal file
19
src/error.rs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
/// Failed to parse the specified string.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ParseError(pub String);
|
||||||
|
|
||||||
|
impl std::fmt::Display for ParseError {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, r#"Failed to parse: "{}""#, self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for ParseError {}
|
||||||
|
|
||||||
|
impl std::ops::Deref for ParseError {
|
||||||
|
type Target = String;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
72
src/lib.rs
Normal file
72
src/lib.rs
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
//!
|
||||||
|
//! # ``EString``
|
||||||
|
//!
|
||||||
|
//! A simple way to parse a string using type annotations.
|
||||||
|
//!
|
||||||
|
//! This package was originally designed for [enve]
|
||||||
|
//!
|
||||||
|
//! [enve]: https://github.com/pleshevskiy/itconfig-rs
|
||||||
|
//!
|
||||||
|
//! ## Getting started
|
||||||
|
//!
|
||||||
|
//! ```rust
|
||||||
|
//! use estring::{SepVec, EString};
|
||||||
|
//!
|
||||||
|
//! type PlusVec<T> = SepVec<T, '+'>;
|
||||||
|
//! type MulVec<T> = SepVec<T, '*'>;
|
||||||
|
//!
|
||||||
|
//! fn main() -> Result<(), estring::ParseError> {
|
||||||
|
//! let res = EString::from("10+5*2+3")
|
||||||
|
//! .parse::<PlusVec<MulVec<f32>>>()?
|
||||||
|
//! .iter()
|
||||||
|
//! .map(|m| m.iter().product::<f32>())
|
||||||
|
//! .sum::<f32>();
|
||||||
|
//!
|
||||||
|
//! assert_eq!(res, 23.0);
|
||||||
|
//! Ok(())
|
||||||
|
//! }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! ## Installation
|
||||||
|
//!
|
||||||
|
//! **The MSRV is 1.51.0**
|
||||||
|
//!
|
||||||
|
//! Add `estring = { version = "0.1", features = ["vec", "number"] }` as a
|
||||||
|
//! dependency in `Cargo.toml`.
|
||||||
|
//!
|
||||||
|
//! `Cargo.toml` example:
|
||||||
|
//!
|
||||||
|
//! ```toml
|
||||||
|
//! [package]
|
||||||
|
//! name = "my-crate"
|
||||||
|
//! version = "0.1.0"
|
||||||
|
//! authors = ["Me <user@rust-lang.org>"]
|
||||||
|
//!
|
||||||
|
//! [dependencies]
|
||||||
|
//! estring = { version = "0.1", features = ["vec", "number"] }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! ## License
|
||||||
|
//!
|
||||||
|
//! **MIT**.
|
||||||
|
//!
|
||||||
|
//! See [LICENSE](./LICENSE) to see the full text.
|
||||||
|
//!
|
||||||
|
#![deny(clippy::pedantic)]
|
||||||
|
#![allow(clippy::module_name_repetitions)]
|
||||||
|
#![deny(missing_docs)]
|
||||||
|
|
||||||
|
pub mod core;
|
||||||
|
mod error;
|
||||||
|
|
||||||
|
pub use crate::core::*;
|
||||||
|
pub use crate::error::ParseError;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
#[test]
|
||||||
|
fn it_works() {
|
||||||
|
let result = 2 + 2;
|
||||||
|
assert_eq!(result, 4);
|
||||||
|
}
|
||||||
|
}
|
Reference in a new issue