dicom_core/value/
person_name.rs

1//! Handling of DICOM values with the PN (person name) value representation
2//! as per PS3.5 sect 6.2.
3use std::fmt::{Display, Formatter};
4
5/// A DICOM _Person Name_ (PN value representation).
6///
7/// Values of this type keep
8/// family name, given name, middle name, prefix and suffix
9/// as borrowed values.
10/// All name components are optional.
11///
12/// # Example
13///
14/// A value of type `PersonName` can be obtained
15/// either by parsing a DICOM formatted string via [`from_text`](PersonName::from_text)
16/// or by using the [builder](PersonNameBuilder) API.
17///
18/// ```
19/// # use dicom_core::value::person_name::PersonName;
20/// let dr_seuss: PersonName = PersonName::from_text("Geisel^Theodor^Seuss^Dr.");
21/// assert_eq!(&dr_seuss.to_string(), "Dr. Theodor Seuss Geisel");
22/// assert_eq!(dr_seuss.prefix(), Some("Dr."));
23/// assert_eq!(dr_seuss.given(), Some("Theodor"));
24/// ```
25#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq)]
26pub struct PersonName<'a> {
27    prefix: Option<&'a str>,
28    family: Option<&'a str>,
29    middle: Option<&'a str>,
30    given: Option<&'a str>,
31    suffix: Option<&'a str>,
32}
33
34/// A builder to construct a [`PersonName`] from its components.
35///
36/// # Example
37///
38/// ```
39/// # use dicom_core::value::person_name::{PersonName, PersonNameBuilder};
40/// let ivan: PersonName = PersonNameBuilder::new()
41///     .with_given("Ivan")
42///     .with_family("Levanov")
43///     .build();
44/// assert_eq!(&ivan.to_dicom_string(), "Levanov^Ivan");
45/// ```
46#[derive(Debug, Copy, Clone)]
47pub struct PersonNameBuilder<'a> {
48    person_name: PersonName<'a>,
49}
50
51impl Display for PersonName<'_> {
52    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
53        let components: &[Option<&str>] = &[
54            self.prefix,
55            self.given,
56            self.middle,
57            self.family,
58            self.suffix,
59        ];
60
61        let mut c_iter = components.iter().flatten().peekable();
62
63        while let Some(component) = c_iter.next() {
64            if c_iter.peek().is_some() {
65                write!(f, "{} ", component)?
66            } else {
67                write!(f, "{}", component)?
68            }
69        }
70        Ok(())
71    }
72}
73
74impl<'a> PersonName<'a> {
75    /// Retrieve PersonName prefix
76    pub fn prefix(&self) -> Option<&str> {
77        self.prefix
78    }
79    /// Retrieve PersonName suffix
80    pub fn suffix(&self) -> Option<&str> {
81        self.suffix
82    }
83    /// Retrieve family name from PersonName
84    pub fn family(&self) -> Option<&str> {
85        self.family
86    }
87    /// Retrieve given name from PersonName
88    pub fn given(&self) -> Option<&str> {
89        self.given
90    }
91    /// Retrieve middle name from PersonName
92    pub fn middle(&self) -> Option<&str> {
93        self.middle
94    }
95    /// Convert the person name into a DICOM formatted string.
96    ///
97    /// Name components are interspersed with a `'^'` separator.
98    /// Leading null components produce a separator,
99    /// while trailing components do not.
100    pub fn to_dicom_string(&self) -> String {
101        let mut name = String::new();
102
103        let components: &[Option<&str>] = &[
104            self.family,
105            self.given,
106            self.middle,
107            self.prefix,
108            self.suffix,
109        ];
110
111        let mut it = components.iter().rev().peekable();
112        // consume trailing None (null) components
113        while it.next_if(|component| component.is_none()).is_some() {}
114
115        let mut it = it.rev().peekable();
116        while let Some(option) = it.next() {
117            if let Some(component) = option {
118                name.push_str(component);
119            }
120            if it.peek().is_some() {
121                name.push('^');
122            }
123        }
124
125        name
126    }
127
128    /// Obtains a person name by interpreting `slice` as a DICOM formatted string.
129    ///
130    /// The DICOM string representation is split by the `'^'` separator
131    /// into its respective components.
132    /// When passing a text value to this function,
133    /// ensure that it contains a single DICOM formatted name.
134    pub fn from_text(slice: &'a str) -> PersonName<'a> {
135        let mut parts = slice.trim().split('^');
136
137        macro_rules! get_component {
138            () => {
139                parts
140                    .next()
141                    .and_then(|s| if s.is_empty() { None } else { Some(s) })
142            };
143        }
144
145        let family = get_component!();
146        let given = get_component!();
147        let middle = get_component!();
148        let prefix = get_component!();
149        let suffix = get_component!();
150
151        PersonName {
152            prefix,
153            given,
154            family,
155            middle,
156            suffix,
157        }
158    }
159
160    /// Retrieve a builder for a person name.
161    ///
162    /// See [`PersonNameBuilder`] for more information.
163    pub fn builder() -> PersonNameBuilder<'a> {
164        PersonNameBuilder::new()
165    }
166}
167
168impl<'a> PersonNameBuilder<'a> {
169    pub fn new() -> PersonNameBuilder<'a> {
170        PersonNameBuilder {
171            person_name: PersonName {
172                prefix: None,
173                family: None,
174                middle: None,
175                given: None,
176                suffix: None,
177            },
178        }
179    }
180
181    /// Insert or update the family name component.
182    pub fn with_family(&mut self, family_name: &'a str) -> &mut Self {
183        self.person_name.family = Some(family_name);
184        self
185    }
186
187    /// Insert or update the middle name component.
188    pub fn with_middle(&mut self, middle_name: &'a str) -> &mut Self {
189        self.person_name.middle = Some(middle_name);
190        self
191    }
192
193    /// Insert or update the given name component.
194    pub fn with_given(&mut self, given_name: &'a str) -> &mut Self {
195        self.person_name.given = Some(given_name);
196        self
197    }
198
199    /// Insert or update the prefix component.
200    pub fn with_prefix(&mut self, name_prefix: &'a str) -> &mut Self {
201        self.person_name.prefix = Some(name_prefix);
202        self
203    }
204
205    /// Insert or update the suffix component.
206    pub fn with_suffix(&mut self, name_suffix: &'a str) -> &mut Self {
207        self.person_name.suffix = Some(name_suffix);
208        self
209    }
210
211    /// Builds the person name with the accumulated components.
212    pub fn build(&self) -> PersonName<'a> {
213        self.person_name
214    }
215}
216
217impl<'a> Default for PersonNameBuilder<'a> {
218    fn default() -> Self {
219        Self::new()
220    }
221}
222
223impl<'a> From<PersonNameBuilder<'a>> for PersonName<'a> {
224    fn from(builder: PersonNameBuilder<'a>) -> Self {
225        builder.build()
226    }
227}
228
229impl<'a> From<&mut PersonNameBuilder<'a>> for PersonName<'a> {
230    fn from(builder: &mut PersonNameBuilder<'a>) -> Self {
231        builder.build()
232    }
233}
234
235#[cfg(test)]
236mod tests {
237    use super::*;
238    #[test]
239    fn test_person_name_to_dicom_string() {
240        let p = PersonNameBuilder::new()
241            .with_given("John")
242            .with_family("Adams")
243            .build();
244        assert_eq!(p.to_dicom_string(), "Adams^John".to_string());
245
246        let p: PersonName = PersonNameBuilder::new().with_prefix("Rev.").into();
247        assert_eq!(p.to_dicom_string(), "^^^Rev.".to_string());
248
249        let p = PersonNameBuilder::new().with_suffix("B.A. M.Div.").build();
250        assert_eq!(p.to_dicom_string(), "^^^^B.A. M.Div.".to_string());
251        let p = PersonName {
252            prefix: Some("Rev."),
253            given: Some("John"),
254            middle: Some("Robert"),
255            family: Some("Adams"),
256            suffix: Some("B.A. M.Div."),
257        };
258        assert_eq!(
259            p.to_dicom_string(),
260            "Adams^John^Robert^Rev.^B.A. M.Div.".to_string()
261        );
262        let p = PersonName {
263            prefix: None,
264            given: Some("John"),
265            middle: Some("Robert"),
266            family: Some("Adams"),
267            suffix: Some("B.A. M.Div."),
268        };
269        assert_eq!(
270            p.to_dicom_string(),
271            "Adams^John^Robert^^B.A. M.Div.".to_string()
272        );
273        let p = PersonName {
274            prefix: Some("Rev."),
275            given: Some("John"),
276            middle: Some("Robert"),
277            family: Some("Adams"),
278            suffix: None,
279        };
280        assert_eq!(p.to_dicom_string(), "Adams^John^Robert^Rev.".to_string());
281        let p = PersonName {
282            prefix: None,
283            given: Some("John"),
284            middle: Some("Robert"),
285            family: Some("Adams"),
286            suffix: None,
287        };
288        assert_eq!(p.to_dicom_string(), "Adams^John^Robert".to_string());
289        let p = PersonName::builder().with_middle("Robert").build();
290        assert_eq!(p.to_dicom_string(), "^^Robert".to_string());
291    }
292    #[test]
293    fn test_person_name_to_string() {
294        let p = PersonName::builder()
295            .with_given("John")
296            .with_family("Adams")
297            .build();
298        assert_eq!(p.to_string(), "John Adams".to_string());
299
300        let p = PersonName::builder().with_prefix("Rev.").build();
301        assert_eq!(p.to_string(), "Rev.".to_string());
302
303        let p = PersonName::builder().with_suffix("B.A. M.Div.").build();
304        assert_eq!(p.to_string(), "B.A. M.Div.".to_string());
305        let p = PersonName {
306            prefix: Some("Rev."),
307            given: Some("John"),
308            middle: Some("Robert"),
309            family: Some("Adams"),
310            suffix: Some("B.A. M.Div."),
311        };
312        assert_eq!(
313            p.to_string(),
314            "Rev. John Robert Adams B.A. M.Div.".to_string()
315        );
316        let p = PersonName {
317            prefix: None,
318            given: Some("John"),
319            middle: Some("Robert"),
320            family: Some("Adams"),
321            suffix: Some("B.A. M.Div."),
322        };
323        assert_eq!(p.to_string(), "John Robert Adams B.A. M.Div.".to_string());
324        let p = PersonName {
325            prefix: Some("Rev."),
326            given: Some("John"),
327            middle: Some("Robert"),
328            family: Some("Adams"),
329            suffix: None,
330        };
331        assert_eq!(p.to_string(), "Rev. John Robert Adams".to_string());
332        let p = PersonName {
333            prefix: None,
334            given: Some("John"),
335            middle: Some("Robert"),
336            family: Some("Adams"),
337            suffix: None,
338        };
339        assert_eq!(p.to_string(), "John Robert Adams".to_string());
340        let p = PersonName::builder().with_middle("Robert").build();
341        assert_eq!(p.to_string(), "Robert".to_string());
342    }
343    #[test]
344    fn person_name_from_slice() {
345        assert_eq!(
346            PersonName::from_text("^^Robert"),
347            PersonName::builder().with_middle("Robert").build()
348        );
349        assert_eq!(
350            PersonName::from_text("^^^Rev."),
351            PersonName::builder().with_prefix("Rev.").build()
352        );
353        assert_eq!(
354            PersonName::from_text("^^^^B.A. M.Div."),
355            PersonName::builder().with_suffix("B.A. M.Div.").build()
356        );
357        assert_eq!(
358            PersonName::from_text("^^Robert"),
359            PersonName::builder().with_middle("Robert").build()
360        );
361        assert_eq!(
362            PersonName::from_text("^John"),
363            PersonName::builder().with_given("John").build()
364        );
365        assert_eq!(
366            PersonName::from_text("Adams"),
367            PersonName::builder().with_family("Adams").build()
368        );
369        assert_eq!(
370            PersonName::from_text("Adams^^^^B.A. M.Div."),
371            PersonName::builder()
372                .with_family("Adams")
373                .with_suffix("B.A. M.Div.")
374                .build()
375        );
376        assert_eq!(
377            PersonName::from_text("Adams^^Robert^^B.A. M.Div."),
378            PersonName {
379                prefix: None,
380                given: None,
381                middle: Some("Robert"),
382                family: Some("Adams"),
383                suffix: Some("B.A. M.Div."),
384            }
385        );
386        assert_eq!(
387            PersonName::from_text("Adams^John^Robert^Rev.^B.A. M.Div."),
388            PersonName {
389                prefix: Some("Rev."),
390                given: Some("John"),
391                middle: Some("Robert"),
392                family: Some("Adams"),
393                suffix: Some("B.A. M.Div."),
394            }
395        );
396        assert_eq!(
397            PersonName::from_text("Adams^ "),
398            PersonName {
399                prefix: None,
400                given: None,
401                middle: None,
402                family: Some("Adams"),
403                suffix: None,
404            }
405        );
406    }
407}