Skip to main content

vcard/tree/value/
adr.rs

1//! # ADR value codec (RFC 6350 6.3.1, RFC 9554)
2//!
3//! [`VcardCodec`] for the structured address: seven `;`-separated components,
4//! eighteen when any RFC 9554 component carries a value.
5
6use alloc::vec;
7
8use crate::{
9    tree::{
10        codec::{VcardCodec, encode::encode_component, mode::VcardEscaper},
11        value::node::VcardValueNode,
12    },
13    value::adr::VcardAdr,
14};
15
16impl<'v> VcardCodec<'v> for VcardAdr<'v> {
17    fn decode(node: &'v VcardValueNode<'_>) -> Self {
18        VcardAdr {
19            po_box: node.decode_at(0),
20            extended: node.decode_at(1),
21            street: node.decode_at(2),
22            locality: node.decode_at(3),
23            region: node.decode_at(4),
24            postal_code: node.decode_at(5),
25            country: node.decode_at(6),
26            room: node.decode_at(7),
27            apartment: node.decode_at(8),
28            floor: node.decode_at(9),
29            street_number: node.decode_at(10),
30            street_name: node.decode_at(11),
31            building: node.decode_at(12),
32            block: node.decode_at(13),
33            subdistrict: node.decode_at(14),
34            district: node.decode_at(15),
35            landmark: node.decode_at(16),
36            direction: node.decode_at(17),
37        }
38    }
39
40    fn encode(&self, escaper: VcardEscaper) -> VcardValueNode<'static> {
41        let mut components = vec![
42            encode_component(&self.po_box, escaper),
43            encode_component(&self.extended, escaper),
44            encode_component(&self.street, escaper),
45            encode_component(&self.locality, escaper),
46            encode_component(&self.region, escaper),
47            encode_component(&self.postal_code, escaper),
48            encode_component(&self.country, escaper),
49        ];
50
51        if self.has_extended_components() {
52            components.extend([
53                encode_component(&self.room, escaper),
54                encode_component(&self.apartment, escaper),
55                encode_component(&self.floor, escaper),
56                encode_component(&self.street_number, escaper),
57                encode_component(&self.street_name, escaper),
58                encode_component(&self.building, escaper),
59                encode_component(&self.block, escaper),
60                encode_component(&self.subdistrict, escaper),
61                encode_component(&self.district, escaper),
62                encode_component(&self.landmark, escaper),
63                encode_component(&self.direction, escaper),
64            ]);
65        }
66
67        VcardValueNode::from_components(components, escaper)
68    }
69}
70
71#[cfg(test)]
72mod tests {
73    use alloc::{borrow::Cow, string::ToString, vec};
74
75    use crate::{
76        tree::{
77            codec::{VcardCodec, mode::VcardEscaper},
78            value::node::VcardValueNode,
79        },
80        value::adr::VcardAdr,
81    };
82
83    #[test]
84    fn decodes_and_reencodes_the_rfc_9554_components() {
85        let node = VcardValueNode::parse(b";;;Quebec;;;Canada;8th wing;;2;2875;boul. Laurier");
86        let adr = VcardAdr::decode(&node);
87
88        assert_eq!(adr.locality, vec![Cow::Borrowed("Quebec")]);
89        assert_eq!(adr.room, vec![Cow::Borrowed("8th wing")]);
90        assert_eq!(adr.floor, vec![Cow::Borrowed("2")]);
91        assert_eq!(adr.street_number, vec![Cow::Borrowed("2875")]);
92        assert_eq!(adr.street_name, vec![Cow::Borrowed("boul. Laurier")]);
93        assert!(adr.has_extended_components());
94
95        // NOTE: eighteen slots come back once any extended component is set.
96        assert_eq!(
97            adr.encode(VcardEscaper::Modern).to_string(),
98            ";;;Quebec;;;Canada;8th wing;;2;2875;boul. Laurier;;;;;;",
99        );
100    }
101
102    #[test]
103    fn a_classic_address_keeps_its_seven_slots() {
104        let adr = VcardAdr {
105            street: vec![Cow::Borrowed("2875 boul. Laurier")],
106            locality: vec![Cow::Borrowed("Quebec")],
107            ..VcardAdr::default()
108        };
109
110        assert!(!adr.has_extended_components());
111        assert_eq!(
112            adr.encode(VcardEscaper::Modern).to_string(),
113            ";;2875 boul. Laurier;Quebec;;;",
114        );
115    }
116}