#![cfg_attr(
feature = "empty",
doc = r#"
For example, non-empty strings:
```
use refining::prelude::{NonEmpty, Refinement};
type NonEmptyStr = Refinement<str, NonEmpty>;
// for instance, we can safely extract the first character
// without worrying about empty strings
fn first(non_empty: &NonEmptyStr) -> char {
let first = non_empty.chars().next().unwrap();
first
}
```
Here, `NonEmptyStr` encodes non-emptiness, so that `first` can not actually panic.
Although for this specific example, one can use [`non-empty-str`][non-empty-str]
for improved ergonomics.
[non-empty-str]: https://docs.rs/non-empty-str
"#
)]
#![cfg_attr(
feature = "regex",
doc = r#"
Or match strings against regular expressions!
```
use refining::prelude::{Matches, Refinement, type_regex};
type_regex!(Natural = "^0|[1-9][0-9]*$");
type NaturalStr = Refinement<str, Matches<Natural>>;
```
"#
)]
#![cfg_attr(
feature = "int",
doc = r#"
And, of course, refine integers!
```
use refining::prelude::{Refinement, u8};
type Level = Refinement<u8, u8::Closed<0, 100>>;
fn print(level: Level) {
println!("{level}%");
}
```
"#
)]
#![cfg_attr(
all(feature = "std", feature = "length", feature = "int", feature = "str"),
doc = r#"
For the final example, let's look at more complex use cases.
```no_run
use std::fmt;
use anyhow::Result;
use tiny_input::tiny_input;
use refining::prelude::*;
type Name = Refinement<String, And<Ascii, LengthClosed<1, 32>>>;
type Charge = Refinement<u8, u8::Closed<0, 100>>;
struct Device {
name: Name,
charge: Charge,
}
impl fmt::Display for Device {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(formatter, "{name} ({charge}%)", name = self.name, charge = self.charge)
}
}
fn main() -> Result<()> {
let name = tiny_input!(as String, "device name: ")?.refine()?;
let charge = tiny_input!(as u8, "device charge: ")?.refine()?;
let device = Device { name, charge };
println!("device: {device}");
Ok(())
}
```
Running this example:
```console
$ cargo run --example device
device name: nekit
device charge: 69
device: nekit (69%)
```
We get the desired output, nice!
For the final note, with the `serde` feature enabled, we can add `#[derive(Serialize, Deserialize)]`
to the `Device` structure, and it will work as expected, so that you can pass around `Device` in APIs.
"#
)]
#![cfg_attr(not(feature = "std"), no_std)]
#![deny(missing_docs)]
#![cfg_attr(docsrs, feature(doc_cfg))]
pub use refining_core as core;
#[cfg(feature = "empty")]
pub use refining_empty as empty;
#[cfg(feature = "length")]
pub use refining_length as length;
#[cfg(feature = "int")]
pub use refining_int as int;
#[cfg(feature = "char")]
pub use refining_char as char;
#[cfg(feature = "str")]
pub use refining_str as str;
#[cfg(feature = "regex")]
pub use refining_regex as regex;
pub mod prelude;