1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
//! # vcard-rs
//!
//! One version-agnostic vCard library: a decoded model and a byte-faithful
//! syntax tree that read and write vCard 2.1 (versitcard), 3.0 (RFC 2426) and
//! 4.0 (RFC 6350) alike.
//!
//! The version is a decoded indicator, never a type parameter: the tree
//! ignores it, and only the codec and the per-property spec branch on it.
//!
//! The crate is `no_std` (with `alloc`), its core is dependency-free, and
//! every dependency sits behind a [cargo feature](#cargo-features).
//!
//! This header is the architecture; the behaviour behind it is specified
//! capability by capability in the repository's cairn/spec folder.
//!
//! ## Postel's law
//!
//! Parsing is maximally liberal: any real card round-trips byte for byte, its
//! folds, its blank lines and its `QUOTED-PRINTABLE` soft breaks included, and
//! an `Unknown` arm on every open enum carries vocabulary no version defines
//! into the model.
//!
//! Strictness lives on the way out: the builder refuses to construct a
//! property the spec forbids, and [`validate`](validator) checks a decoded
//! card against its version's RFC contract.
//!
//! ## The two layers
//!
//! The decoded model ([`vcard`], [`version`], [`prop`], [`param`], [`value`]),
//! with its [`builder`] and [`validator`], is pure data with no dependency on
//! the syntax side, so it can be depended on alone.
//!
//! Property and parameter names and value kinds are closed identity enums
//! ([`VcardPropKind`], [`VcardParamKind`], [`VcardValueKind`]) whose wire
//! spelling is reached through `FromStr` and `Deref`.
//!
//! A card is a [`Vcard`]: a version indicator and its properties, in source
//! order.
//!
//! A property is a [`VcardProp`] of a name, its parameters and one value, the
//! last two open payload enums ([`VcardParam`], [`VcardValue`]) with an
//! `Unknown` arm, so anything outside the model survives.
//!
//! The syntax tree ([`tree`], behind the default `parser` feature) is
//! everything byte-faithful. Its hub is [`VcardCst`], generic nodes
//! reproducing the wire bytes exactly.
//!
//! A line is logical, its folding resolved for every layer above and recorded
//! on its [`VcardWire`] shape, so serialization puts it back where it was and
//! an edit that moves the bytes drops it.
//!
//! [`parse`] reads one card, or a bare RFC 2425 record carrying no `BEGIN` and
//! `END` envelope, and [`parse_many`] iterates a multi-card file.
//!
//! [`decode`] projects a CST onto the decoded [`Vcard`], and [`encode`]
//! projects the model back to a canonical CST.
//!
//! Per-property lens markers ([`VcardPropLens`]) read or edit one line through
//! the byte-preserving [`cursor`]s, and the three-way [`VcardMerge`]
//! reconciles two divergent copies on those same edits.
//!
//! A property value is raw bytes, so a foreign charset (a vCard 2.1 `CHARSET`)
//! survives; a name or a parameter must be UTF-8, as every grammar guarantees.
//! [`to_bytes`] is therefore the faithful serializer, and `Display` a
//! convenience that is lossy only for a non-UTF-8 value.
//!
//! ## The spec layer
//!
//! Each property carries a [`VcardPropSpec`] on its marker, declaring per
//! version the value kinds and parameters it allows, and one vtable dispatch
//! bridges the open [`VcardPropKind`] back to those static specs. It says what
//! the RFC allows rather than how bytes are laid out, so it sits in [`prop`]
//! with the model and needs no parser.
//!
//! That one source of truth has three readers: the decoder picks a value kind
//! from it, [`validate`](validator) checks conformance against it, and the
//! builder rejects illegal construction with it.
//!
//! A card that passes earns a [`VcardValid`] proof. Validity is a runtime
//! predicate rather than a second type, since a conformant card may still
//! carry extensions.
//!
//! ## Content encodings
//!
//! The core transforms no content: a `QUOTED-PRINTABLE` or `BASE64` encoding
//! and a `CHARSET` are surfaced raw with their parameters kept, so nothing is
//! silently transcoded.
//!
//! Only the value grammar (escapes and folding) is resolved, and put back from
//! the line's wire shape on output.
//!
//! Decoding is opt-in, one small `no_std` crate per feature: the value
//! [`cursor`] exposes `quoted_printable` and `charset`, and the binary value
//! exposes [`decode_base64`].
//!
//! ## The JSON representations
//!
//! [`jcard`] is the RFC 7095 spelling of this model in JSON, member for
//! member.
//!
//! [`jscontact`] is the RFC 9553 data model, which is a different model: a
//! card is a Card object of named members, an `ADR` line is a structured
//! Address, and a `TYPE` parameter is a context.
//!
//! Both take a raw [`serde_json::Value`] at the boundary rather than a serde
//! implementation, since one model with two JSON spellings is exactly what
//! serde cannot key. jCard normalizes rather than preserves, while JSContact
//! is lossless through the RFC 9555 escape hatches.
//!
//! ## Cargo features
//!
//! `parser` (default) brings the byte-faithful [`tree`] and its codec, via the
//! `memchr` crate. Everything under [`tree`] is gated on it. The decoded model
//! is always available, and so are the spec layer above it, the [`builder`],
//! the [`validator`] and both JSON representations: none of them reads bytes.
//!
//! Three content decoders are default too, one small crate each:
//! `quoted-printable` decodes `QUOTED-PRINTABLE` value octets, `base64`
//! decodes inline `BASE64` binary values, and `encoding` transcodes a foreign
//! `CHARSET` to text through `encoding_rs` (the WHATWG Encoding Standard).
//!
//! `jcard` adds the RFC 7095 JSON representation, via the `serde_json` crate.
//! `jscontact` adds the RFC 9555 conversion to the RFC 9553 Card, implies
//! `jcard`, whose syntax carries the escape hatch, and pulls no crate of its
//! own.
//!
//! [`VcardPropKind`]: prop::VcardPropKind
//! [`VcardParamKind`]: param::VcardParamKind
//! [`VcardValueKind`]: value::VcardValueKind
//! [`Vcard`]: vcard::Vcard
//! [`VcardProp`]: prop::VcardProp
//! [`VcardParam`]: param::VcardParam
//! [`VcardValue`]: value::VcardValue
//! [`VcardCst`]: tree::cst::VcardCst
//! [`VcardWire`]: tree::wire::VcardWire
//! [`parse`]: tree::cst::VcardCst::parse
//! [`parse_many`]: tree::cst::VcardCst::parse_many
//! [`decode`]: tree::codec::decode
//! [`encode`]: tree::codec::encode
//! [`VcardPropLens`]: tree::prop::lens::VcardPropLens
//! [`cursor`]: tree::value::cursor::VcardValueCursor
//! [`VcardMerge`]: tree::merge::VcardMerge
//! [`to_bytes`]: tree::cst::VcardCst::to_bytes
//! [`VcardPropSpec`]: prop::spec::VcardPropSpec
//! [`VcardValid`]: validator::VcardValid
//! [`decode_base64`]: value::binary::VcardBinary::decode_base64
extern crate alloc;