libsignal_service/
profile_name.rs1use std::fmt::Display;
2
3use serde::{Deserialize, Serialize};
4
5#[derive(PartialEq, Eq, Clone, Debug, Serialize, Deserialize)]
6pub struct ProfileName<S> {
7 pub given_name: S,
8 pub family_name: Option<S>,
9}
10
11impl<S: AsRef<str>> Display for ProfileName<S> {
13 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
14 let given_name = self.given_name.as_ref();
15 match (
16 self.given_name.as_ref().is_empty(),
17 self.family_name.as_ref().map(AsRef::as_ref),
18 ) {
19 (true, None) => Ok(()),
20 (false, None) => write!(f, "{}", given_name),
21 (true, Some(family_name)) => write!(f, "{}", family_name),
22 (false, Some(family_name)) => {
23 if self.is_cjkv() {
24 write!(f, "{} {}", family_name, given_name)
25 } else {
26 write!(f, "{} {}", given_name, family_name)
27 }
28 },
29 }
30 }
31}
32
33impl<S: AsRef<str>> ProfileName<S> {
34 pub fn as_ref(&self) -> ProfileName<&str> {
35 ProfileName {
36 given_name: self.given_name.as_ref(),
37 family_name: self.family_name.as_ref().map(|x| x.as_ref()),
38 }
39 }
40
41 pub fn is_cjkv(&self) -> bool {
42 false
44 }
45
46 pub fn serialize(&self) -> Vec<u8> {
47 if let Some(family_name) = self.family_name.as_ref() {
48 self.given_name
49 .as_ref()
50 .as_bytes()
51 .iter()
52 .chain(std::iter::once(&0u8))
53 .chain(family_name.as_ref().as_bytes())
54 .copied()
55 .collect()
56 } else {
57 self.given_name.as_ref().as_bytes().into()
58 }
59 }
60
61 pub fn is_empty(&self) -> bool {
62 self.given_name.as_ref() == "" && self.family_name.is_none()
63 }
64}
65
66impl ProfileName<String> {
67 pub fn deserialize(
69 data: &[u8],
70 ) -> Result<Option<Self>, std::str::Utf8Error> {
71 let parts: Vec<&[u8]> = data.split(|x| *x == 0).collect();
72 match parts.len() {
73 0 => Ok(None),
74 1 => Ok(Some(Self {
75 given_name: std::str::from_utf8(parts[0])?.to_string(),
76 family_name: None,
77 })),
78 _ => Ok(Some(Self {
79 given_name: std::str::from_utf8(parts[0])?.to_string(),
80 family_name: Some(std::str::from_utf8(parts[1])?.to_string()),
81 })),
82 }
83 }
84}
85
86impl<'de> ProfileName<&'de str> {
87 pub fn empty() -> Self {
88 ProfileName {
89 given_name: "",
90 family_name: None,
91 }
92 }
93
94 pub fn deserialize<'inp: 'de>(
96 data: &'inp [u8],
97 ) -> Result<Option<Self>, std::str::Utf8Error> {
98 let parts: Vec<&[u8]> = data.split(|x| *x == 0).collect();
99 match parts.len() {
100 0 => Ok(None),
101 1 => Ok(Some(Self {
102 given_name: std::str::from_utf8(parts[0])?,
103 family_name: None,
104 })),
105 _ => Ok(Some(Self {
106 given_name: std::str::from_utf8(parts[0])?,
107 family_name: Some(std::str::from_utf8(parts[1])?),
108 })),
109 }
110 }
111}
112
113#[cfg(test)]
114mod tests {
115 use super::*;
116
117 #[test]
118 fn roundtrip_name() {
119 let names = [
120 ("foo", Some("bar")),
121 ("foo", None),
122 ("", None),
123 ("", Some("bar")),
124 ];
125
126 for &(given_name, family_name) in &names {
127 let uut_name = ProfileName::<&str> {
128 given_name,
129 family_name,
130 };
131 let ser = uut_name.serialize();
132 let deserialized =
133 ProfileName::<&str>::deserialize(&ser).expect("utf8");
134 assert_eq!(Some(uut_name), deserialized);
135 }
136 }
137}