pub struct GivenName(/* private fields */);Expand description
One given name, as the work spells it: Mary, or M. where that is all
anybody recorded.
A validating newtype for the same reason Day is one, and the defect that
produced it is the sharpest example in this module of the rule the module
exists for. The formatter used to reduce given names to initials with a
filter_map, so a fragment it could not turn into an initial was dropped
— given = ["Mary", ""] rendered Smith, M. and "Jean--Paul" rendered
J.-P.. Both are plausible authors with part of the recorded name missing,
and a citation that looks authoritative and is partly invented is exactly
what this module refuses to emit. Handling it at the one call site would
have left the spelling available; making the value unconstructible means
no later renderer can reintroduce it, and serde refuses one on the way in
from a file as well.
What is accepted is stated as an allowlist — see
is_given_name_char — rather than as a list of the malformed shapes to
reject. The first attempt at this was the latter, and a space walked through
it: "Mary Ann" was one legal value that rendered Smith, M., dropping
Ann by exactly the mechanism the newtype was introduced to close. A rule
that enumerates the bad separators is a rule waiting for the next separator.
Accepted: Mary, M., Jean-Paul, Ibáñez, N'Golo. Rejected: the empty
string, whitespace alone, Jean--Paul, -Paul, Jean-, "Mary Ann", and
anything carrying a digit, a separator or an invisible character.
Also rejected: a generational suffix (Jr., Sr., II, III, IV).
Those are not given names, and APA prints them in a position this record has
no field for — Smith, J., Jr.. Recorded among the given names they render
as an invented middle initial, Smith, J. J., which is the same fabrication
by another route. Refusing means a real name is unrecordable until the record
grows a field for it, which is the trade this module already makes for a
mononym author: a visible refusal beats a quiet wrong answer.
Implementations§
Source§impl GivenName
impl GivenName
Sourcepub fn new(text: &str) -> Result<Self, NotAGivenName>
pub fn new(text: &str) -> Result<Self, NotAGivenName>
Parse a given name.
Outer whitespace is trimmed and the trimmed form is what is stored: the renderer trims, and a leading space no reader can see must not be able to decide where an entry lands in a list somebody reads. Nothing inside the name is rewritten.
Each hyphen-separated part must begin with a letter and otherwise
contain only given-name characters (is_given_name_char). Beginning with
a letter is what makes GivenName::initial total: every part has a
letter to reduce to, so there is no part it can fail on and therefore
none it could be tempted to skip.
§One value is one name
A given name holding internal whitespace is refused, and this is a
decision rather than a side effect. "Mary Ann" has two readings — two
given names that belong in two elements of given, rendering M. A., or
one compound name rendering M. — and a formatter picking between them
is guessing at what somebody meant. The caller knows; this type does not.
So the ambiguous spelling is not recordable, and the unambiguous one is:
given = [GivenName::new("Mary")?, GivenName::new("Ann")?].
The alternative — accept it and render M. A. by splitting on whitespace
— was rejected because it makes the compound reading unspellable instead,
and a compound given name is a real thing. Refusing leaves both readings
expressible, one of them per element; accepting would silently pick one.
§Errors
Returns NotAGivenName for a blank name, a part not starting with a
letter, any character outside the allowlist (including whitespace), or a
generational suffix.
Sourcepub fn parts(&self) -> impl Iterator<Item = &str>
pub fn parts(&self) -> impl Iterator<Item = &str>
The hyphen-separated parts. Each begins with a letter, by construction, and a part carries no whitespace — so a part is exactly one name and there is exactly one initial to take from it.
Sourcepub fn initial(&self) -> String
pub fn initial(&self) -> String
The initial APA prints for this name: M. for Mary and for M., and
J.-P. for Jean-Paul.
It lives on the record rather than in the formatter because two callers
need it and they must not be allowed to disagree: the formatter prints
it, and Reference::list_order alphabetises on it. APA alphabetises a
list by what the list prints, so ordering on the recorded name instead
lets Mary and M. — one rendered author, two spellings — come out in
an order no reader of the page can account for. One derivation, both
callers; two copies of it is how they came apart in the first place.
map rather than filter_map, deliberately: a part is non-blank by
construction, and if that ever stopped being true this should produce a
visibly wrong initial rather than quietly one part short.
Trait Implementations§
Source§impl<'de> Deserialize<'de> for GivenName
impl<'de> Deserialize<'de> for GivenName
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>,
impl Eq for GivenName
Source§impl Ord for GivenName
impl Ord for GivenName
1.21.0 (const: unstable) · Source§fn max(self, other: Self) -> Selfwhere
Self: Sized,
fn max(self, other: Self) -> Selfwhere
Self: Sized,
1.21.0 (const: unstable) · Source§fn min(self, other: Self) -> Selfwhere
Self: Sized,
fn min(self, other: Self) -> Selfwhere
Self: Sized,
Source§impl PartialOrd for GivenName
impl PartialOrd for GivenName
impl StructuralPartialEq for GivenName
Auto Trait Implementations§
impl Freeze for GivenName
impl RefUnwindSafe for GivenName
impl Send for GivenName
impl Sync for GivenName
impl Unpin for GivenName
impl UnsafeUnpin for GivenName
impl UnwindSafe for GivenName
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<Q, K> Comparable<K> for Q
impl<Q, K> Comparable<K> for Q
impl<T> DeserializeOwned for Twhere
T: for<'de> Deserialize<'de>,
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.