#[seventy]Expand description
Newtype attribute.
Automatically implements the Newtype, Sanitizable, and Validatable
traits.
Other functionality may also be implemented depending on enabled upgrades.
§Upgrades
§as_ref
Implements AsRef for the newtype. The Newtype trait already
has an equivalent to_inner method, but this provides compatability with
APIs that expect AsRef.
use seventy::{core::Newtype, seventy};
#[seventy(upgrades(as_ref))]
pub struct Velocity(f64);
assert_eq!(*Velocity::try_new(70.0).unwrap().as_ref(), 70.0);§deref
Implements Deref for the newtype.
use seventy::{seventy, Newtype};
#[seventy(upgrades(deref))]
pub struct Sentence(String);
let sentence = Sentence::try_new("Hello, World!").unwrap();
assert_eq!(*sentence, "Hello, World!");§display
Implements Display using the inner value’s Display implementation.
use seventy::{seventy, Newtype};
#[seventy(upgrades(display))]
pub struct Email(String);
let email = Email::try_new("example@example.com").unwrap();
assert_eq!(format!("{email}"), "example@example.com");§try_from
Implements TryFrom for the newtype. The Newtype trait
already has the method Newtype::try_new, which is similar to
TryFrom::try_from, however the latter expects a concrete type, whereas
the former Newtype::try_new does not.
use seventy::{seventy, Newtype};
#[seventy(upgrades(try_from))]
pub struct Number(i32);
assert!(Number::try_from(5).is_ok());§deserializable
Implements serde::Deserialize for the newtype. You
must have serde as a dependency!
use seventy::{seventy, Newtype};
#[seventy(upgrades(deserializable))]
pub struct Message(String);
let json = "\"Seventy is a cool crate\"";
let message: Message = serde_json::from_str(json).unwrap();
assert_eq!(message.into_inner(), "Seventy is a cool crate");§serializable
Implements serde::Serialize for the newtype. You must
have serde as a dependency!
use seventy::{seventy, Newtype};
#[seventy(upgrades(serializable))]
pub struct Message(String);
let message = Message::try_new("Seventy is a cool crate").unwrap();
let json = serde_json::to_string(&message).unwrap();
assert_eq!(json, "\"Seventy is a cool crate\"");§bypassable
Enables bypass functionality for the newtype.
use seventy::{
builtins::{compare::*, string::*},
core::{Bypassable, Validatable},
seventy, Newtype,
};
#[seventy(
upgrades(bypassable),
sanitize(trim),
validate(ascii, length::chars(within(5..=20)))
)]
pub struct Username(String);
/* `Bypassable::new_unchecked` */
let username = unsafe { Username::new_unchecked(" username! ") };
assert_eq!(username.as_inner(), " username! ");
/* `Bypassable::new_unsanitized` */
let username = unsafe { Username::new_unsanitized(" username ") }.unwrap();
assert_eq!(username.as_inner(), " username ");
/* `Bypassable::new_unvalidated` */
let username = unsafe { Username::new_unvalidated(" username! ") };
assert_eq!(username.as_inner(), "username!");
/* `Bypassable::as_inner_mut` */
let mut username = Username::try_new("username").unwrap();
// Passes validation.
assert!(Username::validate(username.as_inner()));
// Unsafely mutate the value.
unsafe { username.as_inner_mut() }.push_str("\u{00BF}");
// Fails validation.
assert!(!Username::validate(username.as_inner()));§inherent
Makes the Newtype trait methods callable without the trait
in scope.
The code below fails to compile, since the Newtype trait is not in scope.
use seventy::{builtins::compare::*, seventy};
#[seventy(
validate(within(1..=10))
)]
pub struct Rating(u8);
assert!(Rating::try_new(5).is_ok());The code below compiles due to the inherent upgrade.
use seventy::{builtins::compare::*, seventy};
#[seventy(
upgrades(inherent),
validate(within(1..=10))
)]
pub struct Rating(u8);
assert!(Rating::try_new(5).is_ok());§shared
Sanitizers and validators are typically created each time they are used, which works well for simple validations. However, it may be inefficient for more complex sanitizers and validators to be constructed per-use. This upgrade makes it so each newtype instance shares its sanitizers and validators with other instances.
This upgrade takes away support for generics, and introduces some performance overhead.
§unexposed
Prevents accessing the field directly from the same module.
NOTE:
When this upgrade is enabled, all attributes (such as derives) must be below
the seventy macro.
The code below modifies a newtype’s value by directly accessing the field, which is not good!
use seventy::{seventy, Newtype};
#[seventy()]
pub struct ExposedToModule(i32);
let mut etm = ExposedToModule::try_new(70).unwrap();
etm.0 = 444;
assert_eq!(etm.into_inner(), 444);The code below unexposes the inner field, so the bad code now produces a compilation error.
use seventy::{Newtype, seventy};
#[seventy(upgrades(unexposed))]
pub struct UnexposedToModule(i32);
let mut utm = UnexposedToModule::try_new(70).unwrap();
utm.0 = 444;