icu_experimental/personnames/specifications/
derive_core_prefix.rs

1// This file is part of ICU4X. For terms of use, please see the file
2// called LICENSE at the top level of the ICU4X source tree
3// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).
4
5use crate::personnames::api::{FieldModifier, FieldPart, NameField};
6use alloc::vec;
7use alloc::vec::Vec;
8
9/// Transform the request field in a list of requested field based on the available fields.
10/// a single field can be transformed into 2 fields, or just be removed.
11/// https://www.unicode.org/reports/tr35/tr35-personNames.html#handle-core-and-prefix
12pub fn handle_field_modifier_core_prefix(
13    available_fields: &[&NameField],
14    requested_field: &NameField,
15) -> Vec<NameField> {
16    let is_core = requested_field.modifier.has_field(FieldModifier::Core);
17    let is_prefix = requested_field.modifier.has_field(FieldModifier::Prefix);
18    let is_plain = !is_core && !is_prefix;
19    let mut has_prefix_version_available = false;
20    let mut has_core_version_available = false;
21    let mut has_plain_version_available = false;
22    for &field in available_fields {
23        if field.kind == requested_field.kind {
24            has_plain_version_available |=
25                field.modifier == requested_field.modifier.with_part(FieldPart::Auto);
26            has_prefix_version_available |=
27                field.modifier == requested_field.modifier.with_part(FieldPart::Prefix);
28            has_core_version_available |=
29                field.modifier == requested_field.modifier.with_part(FieldPart::Core);
30        }
31    }
32    let mut result = vec![];
33
34    match (
35        has_prefix_version_available,
36        has_core_version_available,
37        has_plain_version_available,
38    ) {
39        (true, true, true) | (false, false, false) => result.push(*requested_field),
40        (true, false, true) => {
41            if is_core {
42                result.push(NameField {
43                    kind: requested_field.kind,
44                    modifier: requested_field.modifier.with_part(FieldPart::Auto),
45                })
46            } else if is_plain {
47                result.push(*requested_field)
48            }
49        }
50        (false, true, true) | (false, false, true) => {
51            if is_core {
52                result.push(NameField {
53                    kind: requested_field.kind,
54                    modifier: requested_field.modifier.with_part(FieldPart::Auto),
55                })
56            } else {
57                result.push(*requested_field)
58            }
59        }
60        (true, true, false) => {
61            if is_plain {
62                result.push(NameField {
63                    kind: requested_field.kind,
64                    modifier: requested_field.modifier.with_part(FieldPart::Prefix),
65                });
66                result.push(NameField {
67                    kind: requested_field.kind,
68                    modifier: requested_field.modifier.with_part(FieldPart::Core),
69                })
70            } else {
71                result.push(*requested_field)
72            }
73        }
74        (false, true, false) => {
75            if is_plain {
76                result.push(NameField {
77                    kind: requested_field.kind,
78                    modifier: requested_field.modifier.with_part(FieldPart::Core),
79                })
80            } else {
81                result.push(*requested_field)
82            }
83        }
84        (true, false, false) => {
85            if !&is_prefix {
86                result.push(*requested_field)
87            }
88        }
89    }
90
91    result
92}
93
94#[cfg(test)]
95mod tests {
96    use crate::personnames::api::{FieldModifierSet, FieldPart, NameField, NameFieldKind};
97
98    // Each case is named after the combination if the field is present in spec table.
99    // e.g. : cp = core + plain, pc = prefix + core, pp = prefix + plain, pcp = all fields
100
101    #[test]
102    fn test_pcp() {
103        let asserted_parts = &[FieldPart::Prefix, FieldPart::Core, FieldPart::Auto];
104        assert_part(asserted_parts, FieldPart::Prefix, &[FieldPart::Prefix]);
105        assert_part(asserted_parts, FieldPart::Core, &[FieldPart::Core]);
106        assert_part(asserted_parts, FieldPart::Auto, &[FieldPart::Auto]);
107    }
108
109    #[test]
110    fn test_pp() {
111        let asserted_parts = &[FieldPart::Prefix, FieldPart::Auto];
112        assert_part(asserted_parts, FieldPart::Prefix, &[]);
113        assert_part(asserted_parts, FieldPart::Core, &[FieldPart::Auto]);
114        assert_part(asserted_parts, FieldPart::Auto, &[FieldPart::Auto]);
115    }
116
117    #[test]
118    fn test_cp() {
119        let asserted_parts = &[FieldPart::Core, FieldPart::Auto];
120        assert_part(asserted_parts, FieldPart::Prefix, &[FieldPart::Prefix]);
121        assert_part(asserted_parts, FieldPart::Core, &[FieldPart::Auto]);
122        assert_part(asserted_parts, FieldPart::Auto, &[FieldPart::Auto]);
123    }
124
125    #[test]
126    fn test_plain() {
127        let asserted_parts = &[FieldPart::Auto];
128        assert_part(asserted_parts, FieldPart::Prefix, &[FieldPart::Prefix]);
129        assert_part(asserted_parts, FieldPart::Core, &[FieldPart::Auto]);
130        assert_part(asserted_parts, FieldPart::Auto, &[FieldPart::Auto]);
131    }
132
133    #[test]
134    fn test_pc() {
135        let asserted_parts = &[FieldPart::Prefix, FieldPart::Core];
136        assert_part(asserted_parts, FieldPart::Prefix, &[FieldPart::Prefix]);
137        assert_part(asserted_parts, FieldPart::Core, &[FieldPart::Core]);
138        assert_part(
139            asserted_parts,
140            FieldPart::Auto,
141            &[FieldPart::Prefix, FieldPart::Core],
142        );
143    }
144
145    #[test]
146    fn test_c() {
147        let asserted_parts = &[FieldPart::Core];
148        assert_part(asserted_parts, FieldPart::Prefix, &[FieldPart::Prefix]);
149        assert_part(asserted_parts, FieldPart::Core, &[FieldPart::Core]);
150        assert_part(asserted_parts, FieldPart::Auto, &[FieldPart::Core]);
151    }
152
153    #[test]
154    fn test_prefix() {
155        let asserted_parts = &[FieldPart::Prefix];
156        assert_part(asserted_parts, FieldPart::Prefix, &[]);
157        assert_part(asserted_parts, FieldPart::Core, &[FieldPart::Core]);
158        assert_part(asserted_parts, FieldPart::Auto, &[FieldPart::Auto]);
159    }
160
161    #[test]
162    fn test_nothing() {
163        let asserted_parts = &[];
164        assert_part(asserted_parts, FieldPart::Prefix, &[FieldPart::Prefix]);
165        assert_part(asserted_parts, FieldPart::Core, &[FieldPart::Core]);
166        assert_part(asserted_parts, FieldPart::Auto, &[FieldPart::Auto]);
167    }
168
169    fn assert_part(
170        available_parts: &[FieldPart],
171        field_part: FieldPart,
172        expected_parts: &[FieldPart],
173    ) {
174        let available_fields: Vec<NameField> = available_parts
175            .iter()
176            .map(|part: &FieldPart| NameField {
177                kind: NameFieldKind::Given,
178                modifier: FieldModifierSet::part(*part),
179            })
180            .collect::<Vec<NameField>>();
181        let expected_fields: Vec<NameField> = expected_parts
182            .iter()
183            .map(|part| NameField {
184                kind: NameFieldKind::Given,
185                modifier: FieldModifierSet::part(*part),
186            })
187            .collect::<Vec<NameField>>();
188        assert_eq!(
189            super::handle_field_modifier_core_prefix(
190                &available_fields.iter().collect::<Vec<&NameField>>(),
191                &NameField {
192                    kind: NameFieldKind::Given,
193                    modifier: FieldModifierSet::part(field_part),
194                }
195            ),
196            expected_fields
197        )
198    }
199}