pub struct PassportBook {
pub country: String,
pub number: String,
pub issued: Option<NaiveDate>,
pub expires: Option<NaiveDate>,
}Expand description
A passport book — country of issue, book number, and optional effective date range.
Passport data has three properties that make it a poor fit for the
crate’s per-scheme Option<String> national-identifier pattern,
and which this type captures explicitly:
- Scheme-local provenance. A passport book number is only
meaningful alongside its issuing country. The book number
"AB123456"issued by the United Kingdom is a different identifier from"AB123456"issued by the United States; the matcher MUST NOT cross-match them. Provenance lives on thePassportBook::countryfield, not on the field name. - Multi-country. A single worker may hold passports from
multiple countries simultaneously (dual / multiple citizenship).
A
Vec<PassportBook>lets acrate::Workercarry one entry per book without privileging any particular jurisdiction. - Time-varying. When a passport is renewed, the new book has
a different number; the old book number is no longer current
but the worker is unchanged. Worker records may carry the
current book, prior books, or both. Matching treats any shared
(country, number)pair across the two records as evidence that the records refer to the same worker, regardless of issue date.
Construction via PassportBook::new canonicalises both the
country (trimmed, uppercased; must be exactly 2 ASCII letters) and
the number (whitespace stripped, letters uppercased) so two records
carrying different textual layouts of the same book canonicalise to
the same (country, number) key. Date fields are optional metadata
and are not used in matching — they exist for downstream
display and audit. Per-country structural validation is
intentionally not performed; passport formats vary widely and a
case+whitespace canonical form is sufficient for matching.
§Example
use worker_matcher::PassportBook;
use chrono::NaiveDate;
let book = PassportBook::new("gb", " 123 456 789 ")
.expect("valid book")
.with_issued(NaiveDate::from_ymd_opt(2020, 1, 1).unwrap())
.with_expires(NaiveDate::from_ymd_opt(2030, 1, 1).unwrap());
assert_eq!(book.country, "GB");
assert_eq!(book.number, "123456789");
assert!(book.issued.is_some());
// Rejection: country must be exactly 2 ASCII letters.
assert!(PassportBook::new("GBR", "123").is_none());
assert!(PassportBook::new("1A", "123").is_none());
// Rejection: number must canonicalise to a non-empty string.
assert!(PassportBook::new("GB", " ").is_none());Fields§
§country: StringISO 3166-1 alpha-2 country code of issuance, uppercased.
number: StringPassport book number, whitespace-stripped and uppercased.
issued: Option<NaiveDate>Optional issue date (not used in matching).
expires: Option<NaiveDate>Optional expiry date (not used in matching).
Implementations§
Source§impl PassportBook
impl PassportBook
Sourcepub fn new(country: impl AsRef<str>, number: impl AsRef<str>) -> Option<Self>
pub fn new(country: impl AsRef<str>, number: impl AsRef<str>) -> Option<Self>
Construct a passport book, validating and canonicalising the country code (trimmed + uppercased; must be exactly 2 ASCII letters) and the book number (whitespace stripped + uppercased; must be non-empty after stripping).
Returns None for an invalid country code or an empty
canonical number.
use worker_matcher::PassportBook;
let b = PassportBook::new("us", "abc 123 456").unwrap();
assert_eq!(b.country, "US");
assert_eq!(b.number, "ABC123456");Sourcepub fn with_issued(self, date: NaiveDate) -> Self
pub fn with_issued(self, date: NaiveDate) -> Self
Attach an issue date. The date is metadata only — it is NOT used in matching.
use worker_matcher::PassportBook;
use chrono::NaiveDate;
let b = PassportBook::new("GB", "123456789").unwrap()
.with_issued(NaiveDate::from_ymd_opt(2020, 1, 1).unwrap());
assert!(b.issued.is_some());Sourcepub fn with_expires(self, date: NaiveDate) -> Self
pub fn with_expires(self, date: NaiveDate) -> Self
Attach an expiry date. The date is metadata only — it is NOT used in matching.
use worker_matcher::PassportBook;
use chrono::NaiveDate;
let b = PassportBook::new("GB", "123456789").unwrap()
.with_expires(NaiveDate::from_ymd_opt(2030, 1, 1).unwrap());
assert!(b.expires.is_some());Trait Implementations§
Source§impl Clone for PassportBook
impl Clone for PassportBook
Source§fn clone(&self) -> PassportBook
fn clone(&self) -> PassportBook
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for PassportBook
impl Debug for PassportBook
Source§impl<'de> Deserialize<'de> for PassportBook
impl<'de> Deserialize<'de> for PassportBook
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
Source§impl PartialEq for PassportBook
impl PartialEq for PassportBook
Source§fn eq(&self, other: &PassportBook) -> bool
fn eq(&self, other: &PassportBook) -> bool
self and other values to be equal, and is used by ==.Source§impl Serialize for PassportBook
impl Serialize for PassportBook
impl Eq for PassportBook
impl StructuralPartialEq for PassportBook
Auto Trait Implementations§
impl Freeze for PassportBook
impl RefUnwindSafe for PassportBook
impl Send for PassportBook
impl Sync for PassportBook
impl Unpin for PassportBook
impl UnsafeUnpin for PassportBook
impl UnwindSafe for PassportBook
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more