| Crates.io | valust-derive |
| lib.rs | valust-derive |
| version | 0.8.0 |
| created_at | 2025-01-10 09:38:50.590682+00 |
| updated_at | 2025-01-24 13:24:28.279925+00 |
| description | A derive macro for the Valust crate |
| homepage | |
| repository | https://github.com/Embers-of-the-Fire/valust-rs |
| max_upload_size | |
| id | 1511083 |
| size | 81,832 |
The derive macro Valust will emit both an extra structure containing raw
data and an implementation of valust::Validator.
The raw data struct is identical to the structure definition given to the
Valust macro (i.e., struct A { a: A } becomes struct RawA { a: A }, and
struct B(B) becomes struct RawB(B)). The fields are automatically derived by
Valust. Specifically, fields with only valid retain their type, fields with
one or more trans have the type of the first transformer in the first
trans, and fields with forward are determined by the
forward field.
The default naming pattern of the raw data struct is RawXXX. To override it,
use the rename struct attribute.
These attributes can be used on either fields or the structure itself.
forward_attr| Syntax | forward_attr(<attribute>) |
| Description | Add external attribute to the raw data type |
| Example | #[forward_attr(serde(rename_all="camelCase"))] |
valid| Syntax | valid(<valid exprs>) |
| Description | Add a validator to check a field. |
| Example | #[valid(expr(a > 10))] |
Reference: valid expr
trans| Syntax | trans(<trans exprs>) |
| Description | Add a transformer to modify a field. |
| Example | #[trans(expr(try(a.parse::<u32>())))] |
Reference: trans expr
forward| Syntax | forward |
| Description | Forward the field. |
| Example | #[forward] |
rename| Syntax | rename(<ident>) or rename = "<ident>"(not recommended) |
| Description | Rename the raw data structure. |
| Example | #[rename(RawData)] or #[rename = "RawData"] |
forward_derive| Syntax | forward_derive(<derive-items>) |
| Description | Add derive attribute to the raw data structure. |
| Example | #[forward_derive(Debug, Clone)] |
pre| Syntax | pre(<struct-valid-expr>) |
| Description | Add struct-level validator before all field validators. |
| Example | #[pre((magic1 + magic2 == 10, "invalid magic number"))] |
Reference: struct-valid-expr
post| Syntax | post(<struct-valid-expr>) |
| Description | Add struct-level validator after all field validators. |
| Example | #[post((magic1 + magic2 == 10, "invalid magic number"))] |
Reference: struct-valid-expr
<expr>a > 10#[pre(a > 10)](<expr>, <msg>)(b != 0, "`b` must be non-zero")#[pre(b != 0, "`b` must be non-zero")]use valust::Validate;
use valust_derive::Valust;
use valust_utils::convert::parse_to;
#[derive(Debug, Valust)]
#[forward_derive(Debug)]
pub struct Inner {
#[valid(expr(code > 10.0, "code must be greater than 10.0"))]
pub code: f64,
}
#[derive(Debug, Valust)]
#[forward_derive(Debug)]
pub struct Outer {
#[forward]
pub inner: Inner,
#[trans(expr(String => extra.trim()))]
#[trans(func(String => try(parse_to::<u32>)))]
pub extra: u32,
}
#[automatically_derived]
#[derive(Debug)]
pub struct RawInner {
pub code: f64,
}
#[automatically_derived]
#[allow(
non_camel_case_types,
non_snake_case,
unused_variables,
non_upper_case_globals
)]
impl ::valust::Validate for Inner {
type Raw = RawInner;
fn validate(raw: Self::Raw) -> Result<Self, ::valust::error::ValidationError> {
let RawInner { code } = raw;
let mut valust_impl_err_Inner = ::valust::error::ValidationError::new();
valust_impl_err_Inner.check()?;
let mut valust_impl_err_Inner = ::valust::error::ValidationError::new();
fn valust_validate_code(
code: f64,
valust_err_code: &mut ::valust::error::ValidationError,
) -> Option<f64> {
if !({ code > 10.0 }) {
valust_err_code.push_validate_error(
::valust::error::validate::ValidateError {
field: "code",
path: format!("{}", "code"),
value: format!("(f64) {:?}", code),
cause: ::std::option::Option::None,
message: ::std::option::Option::Some(
"code must be greater than 10.0",
),
expression: "{code > 10.0}",
type_name: "f64",
},
);
return None;
}
Some(code)
}
let code: Option<f64> = valust_validate_code(code, &mut valust_impl_err_Inner);
valust_impl_err_Inner.check()?;
let code = code.expect("Unexpected error occurred in processing field `code`");
let mut valust_impl_err_Inner = ::valust::error::ValidationError::new();
valust_impl_err_Inner.check()?;
Ok(Inner { code })
}
}
#[automatically_derived]
#[derive(Debug)]
pub struct RawOuter {
pub inner: ::valust::Raw<Inner>,
pub extra: String,
}
#[automatically_derived]
#[allow(
non_camel_case_types,
non_snake_case,
unused_variables,
non_upper_case_globals
)]
impl ::valust::Validate for Outer {
type Raw = RawOuter;
fn validate(raw: Self::Raw) -> Result<Self, ::valust::error::ValidationError> {
let RawOuter { inner, extra } = raw;
let mut valust_impl_err_Outer = ::valust::error::ValidationError::new();
valust_impl_err_Outer.check()?;
let mut valust_impl_err_Outer = ::valust::error::ValidationError::new();
fn valust_validate_inner(
inner: ::valust::Raw<Inner>,
valust_err_inner: &mut ::valust::error::ValidationError,
) -> Option<Inner> {
let inner: Inner = match ::valust::Validate::validate(inner) {
Ok(v_valust) => v_valust,
Err(e_valust) => {
valust_err_inner.extend_error("inner", e_valust);
return None;
}
};
Some(inner)
}
let inner: Option<Inner> =
valust_validate_inner(inner, &mut valust_impl_err_Outer);
fn valust_validate_extra(
extra: String,
valust_err_extra: &mut ::valust::error::ValidationError,
) -> Option<u32> {
let extra = ({ extra.trim() });
let extra = {
let valust_format_err_clone_extra = extra.clone();
match ((parse_to::<u32>)(extra)) {
::std::result::Result::Ok(valust_v) => valust_v,
::std::result::Result::Err(valust_trans_err_cause) => {
valust_err_extra.push_transform_error(
::valust::error::transform::TransformError {
field: "extra",
path: format!("{}", "extra"),
value: format!(
"(String) {:?}",
valust_format_err_clone_extra
),
cause: ::std::boxed::Box::new(valust_trans_err_cause),
message: ::std::option::Option::Some(
"`extra`'s transform expression fails",
),
expression: "(parse_to :: < u32 >) (extra)",
source_type_name: "String",
target_type_name: "<unknown>",
},
);
return None;
}
}
};
Some(extra)
}
let extra: Option<u32> =
valust_validate_extra(extra, &mut valust_impl_err_Outer);
valust_impl_err_Outer.check()?;
let inner =
inner.expect("Unexpected error occurred in processing field `inner`");
let extra =
extra.expect("Unexpected error occurred in processing field `extra`");
let mut valust_impl_err_Outer = ::valust::error::ValidationError::new();
valust_impl_err_Outer.check()?;
Ok(Outer { inner, extra })
}
}
Forwarding a fieldFields that implement valust::Validator are not automatically recognized by
Valust, but Valust can leverage pre-defined Validator implementations.
Specifically, by using the forward field attribute, Valust will execute the
valust::Validator::validate method of the field's type, automatically
extending the error path field. Additionally, it will automatically change the
corresponding field of the raw data struct to the original data type of that
field.
The raw data type could be inferred by the compiler, so you don't need to
specify it even if you've renamed it.
valust-derive supports regex-based validator expressions using regex.
To enable regex support, you must enable the regex feature for both valust and valust-derive.
Note:
valust > regex feature will enable valust-derive > regex if derive feature is enabled.
renameThough we don't need to specify the raw data type when executing the
validator, we might need to construct them directly. Sadly, due to rust's
language syntax limitations, we cannot construct an unnamed struct using type
alias (i.e. valust::Raw::<Foo>). That's why we may need rename a raw
type.
Displaying huge data may lead to performance issues, as the internal
formatter will clone the data for fear that user-defined expressions might
take the field by-value instead of by-ref.