### Comprehensive Braid Configuration Example Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/configuration.md A detailed example combining multiple Braid configurations: Serde, normalization, custom ref name, custom docs, owned Debug, direct Display, and custom attributes. ```rust #[braid( serde, normalizer, ref_name = "HostRef", ref_doc = "A borrowed reference to a normalized hostname", debug = "owned", display = "impl", owned_attr(must_use = "hostname should not be dropped"), )] pub struct Hostname; impl aliri_braid::Validator for Hostname { type Error = InvalidHostname; fn validate(s: &str) -> Result<(), Self::Error> { if s.is_empty() || s.chars().any(char::is_uppercase) { Err(InvalidHostname) } else { Ok(()) } } } impl aliri_braid::Normalizer for Hostname { fn normalize(s: &str) -> Result, Self::Error> { if s.is_empty() { Err(InvalidHostname) } else if s.chars().any(char::is_uppercase) { Ok(std::borrow::Cow::Owned(s.to_lowercase())) } else { Ok(std::borrow::Cow::Borrowed(s)) } } } ``` -------------------------------- ### Basic Reference-Only Braid Example Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/api-reference/braid-ref-macro.md Demonstrates the basic usage of the `braid_ref` macro for a simple reference-only type without validation or serialization. ```rust use aliri_braid::braid_ref; #[braid_ref(serde, no_std)] pub struct Element; fn main() { let elem = Element::from_static("div"); println!("{}", elem.as_str()); // "div" let parsed: &Element = Element::from_str("span").unwrap(); } ``` -------------------------------- ### Hostname Normalization Example Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/guide.md Illustrates how to use a `Normalizer` for types like `Hostname`. Instances of this type are guaranteed to be in a canonical (lowercase) form, enabling direct comparison. ```rust #[braid(normalizer)] pub struct Hostname; // All instances are guaranteed lowercase let host1 = Hostname::new("EXAMPLE.COM".to_string())?; let host2 = Hostname::new("example.com".to_string())?; assert_eq!(host1, host2); // Both are "example.com" ``` -------------------------------- ### Basic Unvalidated Braid Example Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/api-reference/braid-macro.md Demonstrates creating an unvalidated Braid type `DatabaseName` using `from_static` and using its `as_str` method. Also shows Serde serialization and deserialization. ```rust use aliri_braid::braid; #[braid(serde)] pub struct DatabaseName; fn main() { let db = DatabaseName::from_static("postgres"); println!("{}", db.as_str()); // "postgres" let json = serde_json::to_string(&db).unwrap(); let parsed: DatabaseName = serde_json::from_str(&json).unwrap(); } ``` -------------------------------- ### Owned Type Serialization Example Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/api-reference/owned-type-methods.md Illustrates serialization and deserialization of owned types using Serde. This requires the `serde` attribute to be set to `impl`. ```rust #[braid(serde)] pub struct DatabaseName; fn main() { let db = DatabaseName::from_static("postgres"); let json = serde_json::to_string(&db).unwrap(); let parsed: DatabaseName = serde_json::from_str(&json).unwrap(); } ``` -------------------------------- ### Normalized Braid Example Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/api-reference/braid-macro.md Demonstrates how to create a normalized Braid type that automatically converts input strings to lowercase. This is useful for case-insensitive string comparisons or storage. ```rust use aliri_braid::{braid, Validator, Normalizer}; use std::borrow::Cow; #[braid(normalizer)] pub struct LowercaseName; impl Validator for LowercaseName { type Error = (); fn validate(s: &str) -> Result<(), Self::Error> { if s.is_empty() || s.chars().any(char::is_uppercase) { Err(()) } else { Ok(()) } } } impl Normalizer for LowercaseName { fn normalize(s: &str) -> Result, Self::Error> { if s.is_empty() { Err(()) } else if s.chars().any(char::is_uppercase) { Ok(Cow::Owned(s.to_lowercase())) } else { Ok(Cow::Borrowed(s)) } } } fn main() { // Input is automatically normalized let name = LowercaseName::new("HELLO".to_string()).unwrap(); assert_eq!(name.as_str(), "hello"); } ``` -------------------------------- ### Owned Type Comparison Example Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/api-reference/owned-type-methods.md Demonstrates equality and ordering comparisons between owned and borrowed types. Ensure the necessary traits are implemented for your type. ```rust let db1 = DatabaseName::from_static("postgres"); let db2 = DatabaseName::from_static("postgres"); let db_ref = DatabaseNameRef::from_str("postgres").unwrap(); assert_eq!(db1, db2); assert_eq!(&db1, db_ref); assert!(db1 >= db2); ``` -------------------------------- ### Integrate with Serde for Serialization Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/guide.md Enable Serde serialization and deserialization for braided types by adding the `serde` feature. This example also includes a custom validator for the `Username` type. ```rust #[braid(serde, validator)] pub struct Username; impl Validator for Username { type Error = InvalidUsername; fn validate(s: &str) -> Result<(), Self::Error> { if s.is_empty() || s.eq_ignore_ascii_case("root") { Err(InvalidUsername) } else { Ok(()) } } } fn main() { let user = Username::from_static("alice"); let json = serde_json::to_string(&user).unwrap(); let parsed: Username = serde_json::from_str(&json).unwrap(); } ``` -------------------------------- ### Owned Type Display and Debug Example Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/api-reference/owned-type-methods.md Shows how to use the Display and Debug traits for owned types. These traits are implemented if specified by the `debug` and `display` attributes. ```rust #[braid(debug = "impl", display = "impl")] pub struct DatabaseName; fn main() { let db = DatabaseName::from_static("postgres"); println!("{:?}", db); // Debug println!("{}", db); // Display } ``` -------------------------------- ### Usage Example: Implementing Validator on Braided Type Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/api-reference/validator-trait.md This example demonstrates how to implement the `Validator` trait directly on a braided type to define custom validation logic for `Username`. ```APIDOC ## Example: Implementing Validator on Braided Type ### Description Implement the `Validator` trait directly on the braided type to encapsulate validation logic. ### Usage ```rust use aliri_braid::{braid, Validator}; #[braid(validator)] pub struct Username; impl Validator for Username { type Error = InvalidUsername; fn validate(s: &str) -> Result<(), Self::Error> { if s.is_empty() { Err(InvalidUsername::Empty) } else if s.len() > 32 { Err(InvalidUsername::TooLong) } else { Ok(()) } } } ``` ### Notes - The `InvalidUsername` enum would need to be defined separately to represent specific validation errors. ``` -------------------------------- ### UnixPath Normalizer Implementation Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/api-reference/normalizer-trait.md Demonstrates how to implement the Normalizer trait for a custom UnixPath type. This example shows validation logic and the normalization process, specifically removing duplicate slashes. Use this when you need to enforce specific path formats and clean them up. ```rust use aliri_braid::{braid, Validator, Normalizer}; use std::borrow::Cow; use std::path::Path; #[derive(Debug)] pub enum InvalidPath { Empty, ContainsBackslash, ContainsDotDot, } #[braid(normalizer)] pub struct UnixPath; impl Validator for UnixPath { type Error = InvalidPath; fn validate(s: &str) -> Result<(), Self::Error> { if s.is_empty() { Err(InvalidPath::Empty) } else if s.contains('\\') { Err(InvalidPath::ContainsBackslash) } else if s.contains(".." ) { Err(InvalidPath::ContainsDotDot) } else { Ok(()) } } } impl Normalizer for UnixPath { fn normalize(s: &str) -> Result, Self::Error> { if s.is_empty() { return Err(InvalidPath::Empty); } if s.contains('\\') { return Err(InvalidPath::ContainsBackslash); } if s.contains(".." ) { return Err(InvalidPath::ContainsDotDot); } // Normalize: remove duplicate slashes if s.contains("//") { let normalized = s.split("//") .filter(|s| !s.is_empty()) .collect::>() .join("/"); let result = if s.starts_with('/') { format!("/{{}}", normalized) } else { normalized }; Ok(Cow::Owned(result)) } else { Ok(Cow::Borrowed(s)) } } } fn main() { let path = UnixPath::new("/home//user//documents".to_string()).unwrap(); assert_eq!(path.as_str(), "/home/user/documents"); } ``` -------------------------------- ### Support no_std Environments Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/guide.md Create braids in `no_std` environments using the `no_std` feature. This example demonstrates using `alloc::string::String` and also shows `braid_ref` for pure borrowing without an allocator. ```rust extern crate alloc; use aliri_braid::braid; use alloc::string::String; #[braid(no_std)] pub struct NoStdType; // For pure borrowing without allocator: use aliri_braid::braid_ref; #[braid_ref(no_std)] pub struct NoBorrow; ``` -------------------------------- ### Validated Reference-Only Braid Example Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/api-reference/braid-ref-macro.md Shows how to use the `braid_ref` macro with the `validator` option to create a type that enforces specific string formats. Includes a custom `Validator` implementation. ```rust use aliri_braid::{braid_ref, Validator}; #[braid_ref(validator)] pub struct HttpMethod; impl Validator for HttpMethod { type Error = (); fn validate(s: &str) -> Result<(), Self::Error> { match s { "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "HEAD" | "OPTIONS" => Ok(()), _ => Err(()), } } } fn main() { let get = HttpMethod::from_str("GET").unwrap(); assert!(HttpMethod::from_str("INVALID").is_err()); } ``` -------------------------------- ### SSO-Backed User Type with Validation and Serialization Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/api-reference/custom-string-types.md An example of a custom Username type using CompactString for Short String Optimization (SSO). It includes validation logic and demonstrates transparent serialization. ```rust use aliri_braid::braid; use compact_str::CompactString; #[braid(serde, validator)] pub struct Username(CompactString); impl aliri_braid::Validator for Username { type Error = InvalidUsername; fn validate(s: &str) -> Result<(), Self::Error> { if s.is_empty() || s.len() > 32 { Err(InvalidUsername) } else { Ok(()) } } } fn main() { // Short usernames: no allocation let user1 = Username::from_static("alice"); // Long usernames: allocate only if needed let user2 = Username::from_static("verylongusernamethatexceedssso"); // Serialization works transparently let json = serde_json::to_string(&user1).unwrap(); } ``` -------------------------------- ### Basic Braid Reference Type Generation Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/types.md This example shows the basic usage of the `#[braid_ref]` macro to generate a reference-only type `Element` from a simple struct definition. ```rust #[braid_ref] pub struct Element; // Generates: #[repr(transparent)] pub struct Element(str); ``` -------------------------------- ### Braid with Custom Debug and Display for Ref Type Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/configuration.md Customizes the `Debug` and `Display` implementations for the borrowed reference type of a Braid. This example redacts sensitive information. ```rust use std::fmt; #[braid(debug = "owned", display = "owned")] pub struct Secret; impl fmt::Debug for SecretRef { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str("***REDACTED***") } } impl fmt::Display for SecretRef { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str("***REDACTED***") } } // Owned type delegates to borrowed implementation let secret = Secret::from_static("password123"); println!("{:?}", secret); // Calls SecretRef's Debug impl ``` -------------------------------- ### Implement Lowercase Normalizer Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/guide.md Provides an example of implementing both `Validator` and `Normalizer` for a `Lowercase` type. The `validate` method ensures the input is already lowercase, while `normalize` performs the transformation. ```rust use aliri_braid::{Validator, Normalizer}; use std::borrow::Cow; #[braid(normalizer)] pub struct Lowercase; impl Validator for Lowercase { type Error = (); fn validate(s: &str) -> Result<(), Self::Error> { // validate() checks that s is ALREADY lowercase if s.chars().any(char::is_uppercase) { Err(()) } else { Ok(()) } } } impl Normalizer for Lowercase { fn normalize(s: &str) -> Result, Self::Error> { // normalize() can transform if s.chars().any(char::is_uppercase) { Ok(Cow::Owned(s.to_lowercase())) } else { Ok(Cow::Borrowed(s)) } } } ``` -------------------------------- ### Implement Normalizer Pattern in Rust Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/quick-reference.md Define a custom normalizer for hostnames using the `braid` macro, `Validator`, and `Normalizer` traits. This example normalizes hostnames to lowercase. ```rust use aliri_braid::{braid, Validator, Normalizer}; use std::borrow::Cow; #[braid(normalizer)] pub struct Hostname; impl Validator for Hostname { type Error = (); fn validate(s: &str) -> Result<(), Self::Error> { // Check that s is ALREADY normalized if s.chars().any(char::is_uppercase) { Err(()) } else { Ok(()) } } } impl Normalizer for Hostname { fn normalize(s: &str) -> Result, Self::Error> { // Can transform s if s.chars().any(char::is_uppercase) { Ok(Cow::Owned(s.to_lowercase())) } else { Ok(Cow::Borrowed(s)) } } } ``` -------------------------------- ### Example: Email Validator using `braid` Macro Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/api-reference/validator-trait.md Shows how to create a custom email validator using the `braid` macro. This snippet defines an `Email` struct that implements the `Validator` trait with a simple validation logic and demonstrates its usage in a `main` function. ```rust use aliri_braid::{braid, Validator, from_infallible}; use std::error::Error; #[derive(Debug)] pub struct InvalidEmail; from_infallible!(InvalidEmail); impl std::fmt::Display for InvalidEmail { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { f.write_str("invalid email format") } } impl Error for InvalidEmail {} #[braid(validator)] pub struct Email; impl Validator for Email { type Error = InvalidEmail; fn validate(s: &str) -> Result<(), Self::Error> { // Simple email validation if s.contains('@') && s.contains('.') && s.len() > 3 { Ok(()) } else { Err(InvalidEmail) } } } fn main() { let valid = Email::new("user@example.com".to_string()).unwrap(); let invalid = Email::new("invalid".to_string()); // Err(InvalidEmail) } ``` -------------------------------- ### Customize Display and Debug Implementations Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/guide.md Override the default `Debug` and `Display` implementations for braided types using the `debug` and `display` attributes. This example redacts sensitive information. ```rust use std::fmt; #[braid(debug = "owned", display = "owned")] pub struct Secret; impl fmt::Debug for SecretRef { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str("***REDACTED***") } } impl fmt::Display for SecretRef { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str("***REDACTED***") } } let secret = Secret::from_static("password123"); println!("{:?}", secret); // Prints: ***REDACTED*** ``` -------------------------------- ### Case-Insensitive Email Normalization Example Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/api-reference/normalizer-trait.md Demonstrates how to use the `Normalizer` trait with `#[braid(normalizer, serde)]` to automatically normalize email addresses to lowercase during creation and deserialization. Includes custom error types for validation. ```rust use aliri_braid::{braid, Validator, Normalizer, from_infallible}; use std::borrow::Cow; use std::error::Error; #[derive(Debug)] pub enum InvalidEmail { Empty, NoAtSign, } from_infallible!(InvalidEmail); impl std::fmt::Display for InvalidEmail { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { Self::Empty => f.write_str("email cannot be empty"), Self::NoAtSign => f.write_str("email must contain @"), } } } impl Error for InvalidEmail {} #[braid(normalizer, serde)] pub struct Email; impl Validator for Email { type Error = InvalidEmail; fn validate(s: &str) -> Result<(), Self::Error> { // Validate that s is ALREADY normalized (lowercase) if s.is_empty() { Err(InvalidEmail::Empty) } else if !s.contains('@') { Err(InvalidEmail::NoAtSign) } else if s.chars().any(char::is_uppercase) { Err(InvalidEmail::Empty) // Not normalized } else { Ok(()) } } } impl Normalizer for Email { fn normalize(s: &str) -> Result, Self::Error> { if s.is_empty() { Err(InvalidEmail::Empty) } else if !s.contains('@') { Err(InvalidEmail::NoAtSign) } else if s.chars().any(char::is_uppercase) { Ok(Cow::Owned(s.to_lowercase())) } else { Ok(Cow::Borrowed(s)) } } } fn main() { // Automatically normalizes to lowercase let email = Email::new("User@EXAMPLE.COM".to_string()).unwrap(); assert_eq!(email.as_str(), "user@example.com"); // Deserialization also normalizes let json = r#"USER@EXAMPLE.COM"#; let parsed: Email = serde_json::from_str(json).unwrap(); assert_eq!(parsed.as_str(), "user@example.com"); } ``` -------------------------------- ### Using braid_ref in a Structure Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/api-reference/braid-ref-macro.md Demonstrates how to define and use a struct with a borrowed reference type generated by the braid_ref macro. This example shows the declaration of a Tag struct and its usage within an Article struct, highlighting the borrowing of a reference type. ```rust use aliri_braid::braid_ref; #[braid_ref] pub struct Tag; struct Article<'a> { tag: &'a Tag, // Borrowing a reference type } fn main() { let article_html = "rust"; let tag: &Tag = unsafe { Tag::from_str_unchecked(article_html) }; let article = Article { tag }; } ``` -------------------------------- ### Sensitive Data Handling with Braid Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/quick-reference.md Shows how to configure Braid types for sensitive data, omitting `Clone` and customizing `Debug` and `Display` implementations to mask the actual value. This example uses `ApiSecretRef`. ```rust #[braid(clone = "omit", debug = "owned", display = "owned")] pub struct ApiSecret; impl std::fmt::Debug for ApiSecretRef { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { f.write_str("***") } } impl std::fmt::Display for ApiSecretRef { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { f.write_str("***") } } ``` -------------------------------- ### Zero-Copy Request ID Example Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/api-reference/custom-string-types.md Demonstrates creating a zero-copy custom string type for RequestId using ByteString, which allows for cheap cloning via Arc, beneficial in concurrent scenarios. ```rust use aliri_braid::braid; use bytestring::ByteString; #[braid(serde)] pub struct RequestId(ByteString); // RequestId can be cloned cheaply via Arc—useful in concurrent code async fn handle_request(id: RequestId) { let id_clone = id.clone(); // Cheap clone spawn_task(id_clone).await; } ``` -------------------------------- ### Implementing `From` with `from_infallible!` Macro Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/api-reference/from-infallible-macro.md This example demonstrates how to define a custom error type `InvalidDomain` and use the `from_infallible!` macro to automatically implement the `From` trait. It also shows the necessary implementations for `Debug`, `Display`, and `Error`, along with a `braid` validator that uses this error type. ```rust use aliri_braid::{braid, Validator, from_infallible}; use std::error::Error; use std::fmt; #[derive(Debug, Clone, Copy)] pub enum InvalidDomain { EmptyString, InvalidCharacter { position: usize }, TooLong, } from_infallible!(InvalidDomain); impl fmt::Display for InvalidDomain { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { Self::EmptyString => f.write_str("domain cannot be empty"), Self::InvalidCharacter { position } => { write!(f, "invalid character at position {}", position) } Self::TooLong => f.write_str("domain exceeds 255 characters"), } } } impl Error for InvalidDomain {} #[braid(validator)] pub struct Domain; impl Validator for Domain { type Error = InvalidDomain; fn validate(s: &str) -> Result<(), Self::Error> { if s.is_empty() { return Err(InvalidDomain::EmptyString); } if s.len() > 255 { return Err(InvalidDomain::TooLong); } for (pos, ch) in s.char_indices() { if !ch.is_ascii_alphanumeric() && ch != '.' && ch != '-' { return Err(InvalidDomain::InvalidCharacter { position: pos }); } } Ok(()) } } fn main() { let valid = Domain::new("example.com".to_string()).unwrap(); let invalid = Domain::new("".to_string()); assert!(invalid.is_err()); } ``` -------------------------------- ### Owned Type Example Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/types.md Example of an owned type generated from a struct definition. This specific example shows a `DatabaseName` struct creating a `DatabaseName` owned type wrapping a `String`. ```rust pub struct DatabaseName(String); ``` -------------------------------- ### Borrowed Reference Type Example Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/types.md Example of a borrowed reference type generated from a struct definition. This `DatabaseNameRef` wraps a `str` slice, providing no ownership. ```rust #[repr(transparent)] pub struct DatabaseNameRef(str); ``` -------------------------------- ### Import braid_ref Macro Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/api-reference/braid-ref-macro.md Import the `braid_ref` procedural macro attribute from the `aliri_braid` crate. ```rust use aliri_braid::braid_ref; ``` -------------------------------- ### Get String Slice Reference with as_str Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/api-reference/owned-type-methods.md Use `as_str` to get a string slice reference to the inner value of an owned type. This method does not consume the owned type. ```rust #[braid] pub struct DatabaseName; fn main() { let db = DatabaseName::from_static("postgres"); println!("{}", db.as_str()); // "postgres" } ``` -------------------------------- ### Usage Example: Using an External Validator Type Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/api-reference/validator-trait.md This example shows how to use an external struct that implements the `Validator` trait with a braided type, aliased using the `validator` attribute. ```APIDOC ## Example: Using an External Validator Type ### Description Utilize a separate struct that implements the `Validator` trait, specifying it via the `validator` attribute on the `braid` macro. ### Usage ```rust use aliri_braid::{braid, Validator}; pub struct UsernameValidator; impl Validator for UsernameValidator { type Error = InvalidUsername; fn validate(s: &str) -> Result<(), Self::Error> { // validation logic Ok(()) } } #[braid(validator = "UsernameValidator")] pub struct Username; ``` ### Notes - The `UsernameValidator` struct and its associated `InvalidUsername` error type must be defined and accessible. ``` -------------------------------- ### Create Hostname Instance from Static String Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/api-reference/owned-type-methods.md Use `from_static` to create an instance from a static string slice. This method is efficient but will panic if the provided static string is not already valid and normalized according to the type's rules. ```rust #[braid(normalizer)] pub struct Hostname; fn main() { let host = Hostname::from_static("example.com"); // OK let host = Hostname::from_static("EXAMPLE.COM"); // Panics! (not already normalized) } ``` -------------------------------- ### Accessor Method Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/api-reference/braid-ref-macro.md Provides a way to get a string slice reference to the underlying data of the reference-only type. ```rust pub fn as_str(&self) -> &str ``` -------------------------------- ### Import the Braid Macro Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/api-reference/braid-macro.md Import the `braid` procedural macro attribute from the `aliri_braid` crate. ```rust use aliri_braid::braid; ``` -------------------------------- ### Constructor Methods Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/api-reference/braid-macro.md Methods for creating new instances of Braid types. These vary based on whether validation or normalization is enabled. ```APIDOC ## Constructor Methods ### Unvalidated Types ```rust pub const fn new(value: StringType) -> Self pub fn from_static(raw: &'static str) -> Self ``` ### Validated Types (with `validator` option) ```rust pub fn new(value: StringType) -> Result pub unsafe const fn new_unchecked(value: StringType) -> Self pub fn from_static(raw: &'static str) -> Self // panics if invalid ``` ### Normalized Types (with `normalizer` option) ```rust pub fn new(value: StringType) -> Result pub unsafe const fn new_unchecked(value: StringType) -> Self pub fn from_static(raw: &'static str) -> Self // panics if invalid ``` ``` -------------------------------- ### Generic Wrapper Containing Braided Type Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/types.md An example of a generic struct that holds a braided type (UserId) and a generic parameter T. ```rust struct MyContainer { id: UserId, // Braided type data: T, // Generic parameter } ``` -------------------------------- ### From/Into Implementations Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/api-reference/owned-type-methods.md Provides From/Into implementations for various types. ```APIDOC ## From/Into Implementations ### From<&BorrowedType> ```rust impl From<&BorrowedType> for OwnedType ``` ### Example ```rust let borrowed: &DatabaseNameRef = DatabaseNameRef::from_str("postgres").unwrap(); let owned: DatabaseName = borrowed.into(); ``` ### From> ```rust impl From> for OwnedType ``` ### From> ```rust impl From> for OwnedType ``` For `Cow<'static, BorrowedType>` for normalized types. ``` -------------------------------- ### Create and Normalize Hostname Instance Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/api-reference/owned-type-methods.md Use `new` to create a normalized instance of a type like `Hostname`. This method automatically handles normalization and validation, returning an error if the input is invalid. It avoids allocation if the input is already normalized. ```rust #[braid(normalizer)] pub struct Hostname; impl Validator for Hostname { type Error = InvalidHostname; fn validate(s: &str) -> Result<(), Self::Error> { if s.chars().any(char::is_uppercase) { Err(InvalidHostname) } else { Ok(()) } } } impl Normalizer for Hostname { fn normalize(s: &str) -> Result, Self::Error> { if s.chars().any(char::is_uppercase) { Ok(Cow::Owned(s.to_lowercase())) } else { Ok(Cow::Borrowed(s)) } } } fn main() { let host = Hostname::new("EXAMPLE.COM".to_string()).unwrap(); assert_eq!(host.as_str(), "example.com"); } ``` -------------------------------- ### Basic String Type Usage Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/guide.md Illustrates how standard Rust functions can lead to argument mix-ups with plain strings. This highlights the problem that Aliri Braid aims to solve. ```rust fn connect(host: String, user: String, password: String) -> Result { // Which argument is the password? Easy to mix up! } ``` -------------------------------- ### Aliri Braid Macro Options Cheat Sheet Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/quick-reference.md This cheat sheet outlines various options available for the `braid` and `braid_ref` macros, including validation, normalization, serialization, naming, trait control, type exposure, and attribute customization. ```rust // Validation #[braid(validator)] // Type implements Validator #[braid(validator = "MyValidator")] // External validator type // Normalization (implies validation) #[braid(normalizer)] // Type implements Normalizer + Validator #[braid(normalizer = "MyNormalizer")] // External normalizer type // Serialization #[braid(serde)] // Implement Serialize + Deserialize // Reference type naming #[braid(ref_name = "DbName")] // Custom borrowed type name #[braid(ref_doc = "documentation")] // Custom borrowed type docs // Trait control #[braid(clone = "omit")] // Don't derive Clone #[braid(debug = "owned")] // Owned delegates to borrowed Debug #[braid(display = "omit")] // Don't implement Display #[braid(ord = "impl")] // Implement Ord/PartialOrd // Type exposure #[braid(no_expose)] // Make inner type functions private // Standard library #[braid(no_std)] // Use core/alloc instead of std // Attributes #[braid(owned_attr(must_use))] // Add attributes to owned type #[braid(ref_attr(derive(Eq)))] // Add attributes to borrowed type ``` -------------------------------- ### Migrating from String to CompactString for a Custom Type Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/api-reference/custom-string-types.md Shows how to change the backing string type of a Braid-generated struct from `String` to `CompactString` while maintaining a stable public API. ```rust // Original #[braid] pub struct UserId; // Later, switch to SSO use compact_str::CompactString; #[braid] pub struct UserId(CompactString); ``` -------------------------------- ### Encapsulate Access with Modules Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/guide.md Use Rust modules to control access to internal fields of your braided types. This example shows how to define and export a module for `AmazonArnBuf` and `AmazonArn`. ```rust pub mod arn { use aliri_braid::braid; #[braid] pub struct AmazonArnBuf; impl AmazonArnBuf { pub fn add_segment(&mut self, segment: &str) { self.0.push(':'); self.0.push_str(segment); } } impl AmazonArn { pub fn service(&self) -> Option<&str> { self.as_str().split(':').nth(2) } } } pub use arn::{AmazonArnBuf, AmazonArn}; ``` -------------------------------- ### Implement Validator on Braided Type Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/api-reference/validator-trait.md Example of implementing the Validator trait directly on a custom braided type (Username). This approach embeds validation logic within the type itself. ```rust use aliri_braid::{braid, Validator}; #[braid(validator)] pub struct Username; impl Validator for Username { type Error = InvalidUsername; fn validate(s: &str) -> Result<(), Self::Error> { if s.is_empty() { Err(InvalidUsername::Empty) } else if s.len() > 32 { Err(InvalidUsername::TooLong) } else { Ok(()) } } } ``` -------------------------------- ### Aliri Braid Dependency with Default Features (alloc enabled) Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/quick-reference.md Include `aliri_braid` in your `Cargo.toml` with default features enabled, which typically includes `alloc`. This is the standard way to add the crate for most projects. ```TOML [dependencies] aliri_braid = "0.4" # Default: alloc enabled ``` -------------------------------- ### Using Normalized Braid as HashMap Key Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/api-reference/normalizer-trait.md Demonstrates how to use a normalized braid as a key in a HashMap by explicitly converting it to a string slice. This is necessary because normalized braids do not implement `Borrow`. ```rust use std::collections::HashMap; let mut map: HashMap = HashMap::new(); let key = Email::new("USER@EXAMPLE.COM".to_string()).unwrap(); map.insert(key.as_str().to_string(), "value".to_string()); ``` -------------------------------- ### Implement Simple Validator in Rust Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/quick-reference.md Define a custom validator for email format using the `braid` macro and `Validator` trait. This example shows how to create a simple validation rule. ```rust use aliri_braid::{braid, Validator, from_infallible}; use std::error::Error; #[derive(Debug)] pub struct InvalidEmail; from_infallible!(InvalidEmail); impl std::fmt::Display for InvalidEmail { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { f.write_str("invalid email") } } impl Error for InvalidEmail {} #[braid(validator)] pub struct Email; impl Validator for Email { type Error = InvalidEmail; fn validate(s: &str) -> Result<(), Self::Error> { if s.contains('@') { Ok(()) } else { Err(InvalidEmail) } } } ``` -------------------------------- ### Strongly-Typed String Usage with Braids Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/guide.md Demonstrates how Aliri Braid's generated types prevent argument mix-ups at compile time, improving code clarity and safety. ```rust fn connect(host: Hostname, user: Username, password: Password) -> Result { // Type system prevents mixing up arguments } ``` -------------------------------- ### new Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/api-reference/owned-type-methods.md Creates a new instance of an owned type, automatically normalizing the input string if necessary. It returns a Result, indicating success with the normalized instance or an error if normalization fails. ```APIDOC ## new ### Description Creates a new instance, normalizing the input if necessary. ### Signature ```rust pub fn new(value: StringType) -> Result ``` ### Parameters #### Path Parameters - **value** (StringType) - Required - The string value to wrap and normalize ### Returns - `Ok(instance)` if normalization succeeds, `Err(error)` otherwise ### Errors - Returns the normalizer's error type if the input cannot be normalized ### Behavior - Input is automatically normalized - If normalization is successful, the returned instance contains the normalized value - No allocation occurs if the input is already normalized ### Example ```rust #[braid(normalizer)] pub struct Hostname; impl Validator for Hostname { type Error = InvalidHostname; fn validate(s: &str) -> Result<(), Self::Error> { if s.chars().any(char::is_uppercase) { Err(InvalidHostname) } else { Ok(()) } } } impl Normalizer for Hostname { fn normalize(s: &str) -> Result, Self::Error> { if s.chars().any(char::is_uppercase) { Ok(Cow::Owned(s.to_lowercase())) } else { Ok(Cow::Borrowed(s)) } } } fn main() { let host = Hostname::new("EXAMPLE.COM".to_string()).unwrap(); assert_eq!(host.as_str(), "example.com"); } ``` ``` -------------------------------- ### Custom String Types with Braid Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/quick-reference.md Shows how to use Braid with various custom string types like `CompactString`, `ByteString`, and `SmartString` by specifying them directly in the struct definition. ```rust use compact_str::CompactString; #[braid] pub struct UserId(CompactString); // Wraps CompactString instead of String use bytestring::ByteString; #[braid] pub struct RequestId(ByteString); // Wraps ByteString use smartstring::{SmartString, LazyCompact}; #[braid] pub struct SessionId(SmartString); ``` -------------------------------- ### Import the from_infallible macro Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/api-reference/from-infallible-macro.md Import the `from_infallible` macro from the `aliri_braid` crate. ```rust use aliri_braid::from_infallible; ``` -------------------------------- ### Define LowercaseName Normalizer and Validator Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/api-reference/normalizer-trait.md Example of implementing both Validator and Normalizer traits for a LowercaseName type. The validator checks if the string is already normalized (no uppercase chars), and the normalizer converts it to lowercase if necessary. ```rust use aliri_braid::{braid, Validator, Normalizer}; use std::borrow::Cow; #[braid(normalizer)] pub struct LowercaseName; impl Validator for LowercaseName { type Error = InvalidName; fn validate(s: &str) -> Result<(), Self::Error> { // This validates that s is ALREADY normalized if s.is_empty() { Err(InvalidName::Empty) } else if s.chars().any(char::is_uppercase) { Err(InvalidName::NotNormalized) } else { Ok(()) } } } impl Normalizer for LowercaseName { fn normalize(s: &str) -> Result, Self::Error> { if s.is_empty() { Err(InvalidName::Empty) } else if s.chars().any(char::is_uppercase) { Ok(Cow::Owned(s.to_lowercase())) } else { Ok(Cow::Borrowed(s)) } } } ``` -------------------------------- ### Braid with Custom Ref Name Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/configuration.md Configures a Braid type to use a custom name for its borrowed reference type. This example names the borrowed type 'UserLogin' instead of the default derived name. ```rust #[braid(ref_name = "UserLogin")] pub struct UsernameBuf; ``` -------------------------------- ### no_std Compilation Configuration (Reference-only) Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/quick-reference.md Configure `braid_ref` for `no_std` environments when only a reference type is needed and no heap allocation is required. This is the most minimal configuration. ```Rust // no_std without alloc (reference-only) #[braid_ref(no_std)] pub struct MyRef; ``` -------------------------------- ### TryFrom Implementations Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/api-reference/owned-type-methods.md Provides TryFrom implementations for unvalidated and validated types. ```APIDOC ## TryFrom Implementations For unvalidated types only, `From` and `From<&str>`: ```rust #[braid] pub struct Unvalidated; impl From for Unvalidated { /* ... */ } impl From<&str> for Unvalidated { /* ... */ } ``` For validated/normalized types, `TryFrom` and `TryFrom<&str>`: ```rust #[braid(validator)] pub struct Validated; impl TryFrom for Validated { /* ... */ } impl TryFrom<&str> for Validated { /* ... */ } ``` ``` -------------------------------- ### Implement Cow<'static, str> for Config Values Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/api-reference/custom-string-types.md Wrap `std::borrow::Cow<'static, str>` to handle owned or borrowed strings, deferring allocation decisions and allowing references to static data without copying. ```rust use aliri_braid::braid; use std::borrow::Cow; #[braid] pub struct ConfigValue(Cow<'static, str>); ``` -------------------------------- ### Get String Slice Reference with as_str Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/api-reference/borrowed-type-methods.md Use `as_str` to obtain a string slice reference to the inner value of a borrowed type. This method is useful when you need to read the string data without taking ownership. ```rust #[braid] pub struct DatabaseName; fn main() { let db_ref = DatabaseNameRef::from_str("postgres"); println!("{}", db_ref.as_str()); // "postgres" } ``` -------------------------------- ### no_std Compilation Configuration (Requires alloc) Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/quick-reference.md Configure `braid` for `no_std` environments that still require the `alloc` library. This is useful for embedded systems or environments where `std` is not available but heap allocation is. ```Rust extern crate alloc; // Requires alloc, not std #[braid(no_std)] pub struct MyType; ``` -------------------------------- ### Create and Manipulate Unvalidated Borrowed Types Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/quick-reference.md Use these methods to create and work with unvalidated borrowed types. `from_str` and `from_static` create references, `as_str` gets a string slice, and `to_owned` converts to an owned type. ```rust let ref_val = MyTypeRef::from_str("data"); // &MyTypeRef let ref_val = MyTypeRef::from_static("data"); // &'static MyTypeRef let s: &str = ref_val.as_str(); // Get string slice let owned: MyType = ref_val.to_owned(); // Convert to owned ``` -------------------------------- ### Using Braids as Strongly-Typed Strings Source: https://github.com/neoeinstein/aliri_braid/blob/main/README.md Demonstrates how to create and pass braid instances as strongly-typed, immutable strings. Braids can be passed by value or by reference to functions expecting their strong types. ```rust fn take_strong_string(n: DatabaseName) {} fn borrow_strong_string(n: &DatabaseNameRef) {} let owned = DatabaseName::new(String::from("mongo")); borrow_strong_string(&owned); take_strong_string(owned); ``` -------------------------------- ### Fixed-Size Country Code Example Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/api-reference/custom-string-types.md Illustrates defining a fixed-size custom string type for CountryCode using TinyStr2, with a custom validator to ensure it consists of exactly two uppercase ASCII characters. This type avoids heap allocations. ```rust use aliri_braid::braid_ref; use tinystr::TinyStr2; #[braid_ref(validator)] pub struct CountryCode(TinyStr2); impl aliri_braid::Validator for CountryCode { type Error = (); fn validate(s: &str) -> Result<(), Self::Error> { if s.len() != 2 || !s.chars().all(char::is_ascii_uppercase) { Err(()) } else { Ok(()) } } } fn main() { let us = CountryCode::from_str("US").unwrap(); // 2 bytes on stack, no allocation ever } ``` -------------------------------- ### Aliri Braid Project Directory Structure Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/INDEX.md This snippet shows the directory structure of the Aliri Braid project, indicating the location of key documentation files and API reference modules. ```text /workspace/home/output/ ├── README.md # Main entry point ├── INDEX.md # This file ├── quick-reference.md # Cheat sheet (syntax, patterns) ├── guide.md # Conceptual guide ├── configuration.md # All macro options ├── types.md # Type definitions and generated types └── api-reference/ ├── braid-macro.md # #[braid] attribute macro ├── braid-ref-macro.md # #[braid_ref] attribute macro ├── from-infallible-macro.md # Helper macro for error types ├── validator-trait.md # Validator trait documentation ├── normalizer-trait.md # Normalizer trait documentation ├── owned-type-methods.md # Methods on owned braid types ├── borrowed-type-methods.md # Methods on borrowed braid types ├── ref-only-type-methods.md # Methods on #[braid_ref] types └── custom-string-types.md # Using custom string wrappers ``` -------------------------------- ### take Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/api-reference/owned-type-methods.md Unwraps and consumes the owned type, returning the inner string. ```APIDOC ## take ### Description Unwraps and consumes the owned type, returning the inner string. ### Signature ```rust pub fn take(self) -> StringType ``` ### Parameters None ### Returns The inner string type ### Example ```rust #[braid] pub struct DatabaseName; fn main() { let db = DatabaseName::from_static("postgres"); let inner: String = db.take(); println!("{}", inner); // "postgres" } ``` ``` -------------------------------- ### from_static Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/api-reference/borrowed-type-methods.md Creates a static reference from a static string. This method is `const` and requires the input string to be already normalized, otherwise it will panic. ```APIDOC ## from_static ### Description Creates a static reference from a static string. ### Signature ```rust pub const fn from_static(raw: &'static str) -> &'static Self ``` ### Parameters #### Path Parameters - **raw** (`&'static str`) - Required - A static string slice ### Returns A static reference if the string is normalized ### Panics If the provided string is not already in normalized form ### Attributes `const`, `#[track_caller]` ### Example ```rust #[braid(normalizer)] pub struct Hostname; fn main() { // Only works if string is already normalized let host = HostnameRef::from_static("example.com"); assert_eq!(host.as_str(), "example.com"); } ``` ``` -------------------------------- ### Normalized Identifiers with Braid Source: https://github.com/neoeinstein/aliri_braid/blob/main/_autodocs/quick-reference.md Demonstrates how to use the `normalizer` attribute with Braid to create types that automatically normalize their string representation. Includes Serde integration. ```rust #[braid(serde, normalizer)] pub struct Hostname; #[braid(serde, normalizer)] pub struct EmailAddress; ```