Schemas

Strings

vld::string() — length, patterns, transforms, coercion and more than 40 built-in formats.

vld::string() returns a ZString whose output is String. Checks are chained and all of them run, so one parse can report several issues.

use vld::prelude::*;

let username = vld::string()
    .trim()
    .to_lowercase()
    .min(3)
    .max(20)
    .alphanumeric();

assert_eq!(username.parse(r#""  Ada42 ""#).unwrap(), "ada42");

Length

Lengths count characters (Unicode scalar values), not bytes.

MethodCheckIssue
min(n)at least n characterstoo_small (origin string)
max(n)at most n characterstoo_big (origin string)
len(n)exactly n charactersinvalid_length
non_empty()at least one charactertoo_small

Content

MethodCheck
starts_with("pre")prefix
ends_with("suf")suffix
contains("sub")substring
pattern(r"...")regular expression (feature regex); emitted as JSON Schema pattern. Takes the source (panics on an invalid one, like Regex::new(..).unwrap()) or a prebuilt vld::rules::Pattern
rule(r)a reusable custom rule
// feature = "regex"
let sku = vld::string().pattern(r"^[A-Z]{3}-\d{4}$");
assert!(sku.parse(r#""ABC-1234""#).is_ok());

Most checks need no regex: every format below is a hand-written parser. Reach for pattern only for shapes that are not built in, and prefer a rule when the check is easier to write in Rust.

Transforms and coercion

Transforms run before the checks, in the order they were added.

MethodEffect
trim()strip leading and trailing whitespace
to_lowercase()lowercase the input
to_uppercase()uppercase the input
coerce()accept numbers and booleans and turn them into text (42 → "42")

Formats

Every format method has a _msg twin that takes a custom message (email_msg("...")). A failed format check reports IssueCode::InvalidString { validation }, key invalid_string. Each format also sets the JSON Schema format keyword.

Network

MethodAccepts
email()email address
url()http / https URL
url_strict()public http / https URL: real host, not localhost, private, loopback, link-local or unspecified addresses (IPv4-mapped IPv6 included). Feature string-advanced
uri()any URI (feature string-advanced)
ip()IPv4 or IPv6 address
ipv4() / ipv6()one address family (IPv6 accepts IPv4-mapped forms)
cidr()IPv4 / IPv6 CIDR block with a decimal prefix
mac()MAC address xx:xx:xx:xx:xx:xx
hostname()DNS hostname

Identifiers

MethodAccepts
uuid()any UUID
uuid_v1() / uuid_v4() / uuid_v7()a specific UUID version (feature string-advanced)
cuid2()CUID2: 2–32 lowercase alphanumerics starting with a letter
ulid()26-character Crockford Base32 ULID
nanoid()Nano ID alphabet (alphanumerics, _, -)
slug()URL slug [a-z0-9-]
semver()MAJOR.MINOR.PATCH with an optional v prefix
semver_full()full semantic version parsed by the semver crate (feature string-advanced)
jwt()JWT-shaped token header.payload.signature (base64url parts; the signature is not verified)
credit_card()12–19 digits with optional spaces or dashes, Luhn-checked
phone()international phone: leading +, 8–15 digits, optional spaces, dashes, parentheses
phone_e164_strict()strict E.164, checked with phonenumber (feature string-advanced)
currency_code()three uppercase letters (ISO 4217 shape)
country_code()ISO 3166 alpha-2
locale()ll or ll-RR (en, en-US)
cron()cron expression with 5 or 6 fields
color()#RRGGBB, #RRGGBBAA, rgb(...), hsl(...)

Text

MethodAccepts
ascii()ASCII only
alpha()ASCII letters only
alphanumeric()ASCII letters and digits
lowercase() / uppercase()already lower / upper case (use to_lowercase() to convert instead)
emoji()non-empty, emoji only
json()a string that contains exactly one JSON document

Dates and times as strings

These keep the value a String. To get typed dates, use the date schemas.

MethodAccepts
iso_date()YYYY-MM-DD with a real day of month
iso_datetime()YYYY-MM-DDTHH:MM:SS[.frac] (seconds required, T or t), optional Z / z / ±HH:MM; the same grammar as vld::chrono::datetime()
iso_time()HH:MM[:SS[.frac]]

Encodings

MethodAccepts
base64()standard Base64 with padding
base64url()URL-safe alphabet (-, _), padding optional; rejects + and /
hex()hexadecimal characters only

To decode into bytes instead of keeping text, use vld::bytes().base64().

Messages

let name = vld::string()
    .type_error("Name must be text")
    .min_msg(2, "Name is too short")
    .email_msg("Please enter a valid email");

// Or override many checks by key at once:
let code = vld::string().min(3).max(8).with_messages(|key| match key {
    "too_small" => Some("Too short".into()),
    "too_big" => Some("Too long".into()),
    _ => None,
});

with_messages keys are too_small, too_big, invalid_length, non_empty, invalid_regex (for pattern), a rule's key, invalid_starts_with, invalid_ends_with, invalid_contains and invalid_<format> (invalid_email, invalid_url, invalid_uuid, …). A _msg message wins over with_messages. More in Custom messages.