Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Getting Started

Installation

Add moxy to your Cargo.toml:

[dependencies]
moxy = "0.0.4"

To enable all optional features:

[dependencies]
moxy = { version = "0.0.4", features = ["full"] }

Tip

Enable full during development to get access to all features, then trim to only what you need before publishing.

Or pick individual features:

[dependencies]
moxy = { version = "0.0.4", features = ["json", "color"] }

See Feature Flags for details on each feature.

Basic Usage

Import the derives you need from moxy:

use moxy::{Default, Deref, Display};

Display

Add #[derive(Display)] to get a std::fmt::Display implementation:

use moxy::Display;

#[derive(Display)]
struct User {
    name: String,
    email: String,
}

let user = User {
    name: "John".into(),
    email: "john@example.com".into(),
};

println!("{user}");
// User { name: John, email: john@example.com }

Deref

Add #[derive(Deref)] to delegate std::ops::Deref to an inner field:

use moxy::Deref;

#[derive(Deref)]
struct Email(String);

let email = Email("john@example.com".into());
assert_eq!(email.len(), 16);

Build

Add #[derive(Build)] to generate a fluent builder. Annotate each field you want in the builder with #[moxy(build)]:

use moxy::Build;

#[derive(Build, Default)]
struct Config {
    #[moxy(build)]
    pub host: String,
    #[moxy(build(default = 8080u16))]
    pub port: u16,
}

let config = Config::new().host("localhost").build();
assert_eq!(config.host, "localhost");
assert_eq!(config.port, 8080);

Default

Note

use moxy::Default shadows Rust’s built-in Default derive. If you need both in the same module, qualify the std one as #[derive(std::default::Default)].

Add #[derive(Default)] and annotate fields with #[moxy(default = expr)] to generate a custom Default implementation:

use moxy::Default;

#[derive(Default)]
struct Config {
    #[moxy(default = "localhost")]
    pub host: String,
    #[moxy(default = 8080u16)]
    pub port: u16,
    pub debug: bool,
}

let config = Config::default();
assert_eq!(config.host, "localhost");
assert_eq!(config.port, 8080);
assert_eq!(config.debug, false);

Get

Add #[derive(Get)] and annotate fields with #[moxy(get)] to generate getters:

use moxy::Get;

#[derive(Get)]
struct User {
    #[moxy(get)]
    name: String,
    #[moxy(get)]
    bio: Option<String>,
}

let user = User { name: "alice".into(), bio: Some("hello".into()) };
assert_eq!(user.name(), "alice");
assert_eq!(user.bio(), Some("hello"));

Set

Add #[derive(Set)] and annotate fields with #[moxy(set)] to generate setters with Into<T> coercion:

use moxy::Set;

#[derive(Set)]
struct Config {
    #[moxy(set)]
    host: String,
    #[moxy(set)]
    port: u16,
}

let mut cfg = Config { host: String::new(), port: 0 };
cfg.set_host("localhost").set_port(8080_u16);
assert_eq!(cfg.host, "localhost");

Union

Add #[derive(Union)] to an enum to generate is_*(), as_*(), and to_*() variant accessors:

use moxy::Union;

#[derive(Union)]
enum Value {
    Text(String),
    Number(i32),
    Empty,
}

let v = Value::Text("hello".into());
assert!(v.is_text());
assert_eq!(v.as_text(), Some(&"hello".to_string()));
assert_eq!(v.to_text(), Some("hello".to_string()));
assert!(!v.is_number());

unionize!

Use unionize! to generate a union-type enum with variant methods and From impls in one step:

moxy::unionize! {{
    Text => String,
    Number => i32,
    Flag => bool,
} as pub Value}

let v: Value = "hello".to_string().into();
assert!(v.is_text());

Forward

Add #[derive(Forward)] and declare method signatures on fields to generate forwarding methods:

use moxy::Forward;

#[derive(Forward)]
struct Wrapper {
    #[moxy(forward(
        fn len(&self) -> usize,
        fn is_empty(&self) -> bool,
    ))]
    inner: Vec<String>,
}

let w = Wrapper { inner: vec!["hello".into()] };
assert_eq!(w.len(), 1);
assert!(!w.is_empty());

Next Steps