Skip to content

Commit 1c13830

Browse files
committed
add utility functions
1 parent 3f29382 commit 1c13830

File tree

3 files changed

+156
-40
lines changed

3 files changed

+156
-40
lines changed

src/card.rs

Lines changed: 36 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! The primary Card object as defined in RFC 9553
22
3-
use std::collections::HashMap;
3+
use std::{collections::HashMap, str::FromStr};
44

55
use serde::{Deserialize, Serialize};
66
use serde_json::Value;
@@ -14,7 +14,7 @@ use crate::{
1414
use crate::{AddressComponent, AddressComponentKind, NameComponent};
1515

1616
/// Represents the primary Card object as defined in RFC 9553, storing metadata and contact properties.
17-
#[derive(Serialize, Deserialize, Debug, Clone)]
17+
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
1818
#[serde(rename_all = "camelCase")]
1919
pub struct Card {
2020
/// The JSContact type of the Card object. Must be "Card".
@@ -180,41 +180,13 @@ impl Card {
180180
}
181181
}
182182

183-
/// Wrapper around serde_json
184-
/// # Errors
185-
/// Will return an error if the input is not a valid Card object.
186-
pub fn from_slice(json_slice: &[u8]) -> Result<Self, serde_json::Error> {
187-
serde_json::from_slice(json_slice)
188-
}
189-
190183
/// Wrapper around serde_json
191184
/// # Errors
192185
/// Will return an error if the input is not a valid Card object.
193186
pub fn from_reader<R: std::io::Read>(reader: R) -> Result<Self, serde_json::Error> {
194187
serde_json::from_reader(reader)
195188
}
196189

197-
/// Wrapper around serde_json
198-
/// # Errors
199-
/// Will return an error if the input is not a valid Card object.
200-
pub fn from_value(value: Value) -> Result<Self, serde_json::Error> {
201-
serde_json::from_value(value)
202-
}
203-
204-
/// Wrapper around serde_json
205-
/// # Errors
206-
/// Will return an error if the input is not a valid Card object.
207-
pub fn try_from_str(json_string: String) -> Result<Self, serde_json::Error> {
208-
serde_json::from_str(&json_string)
209-
}
210-
211-
/// Wrapper around serde_json
212-
/// # Errors
213-
/// Will return an error if the input is not a valid Card object.
214-
pub fn serialize_str(&self) -> Result<String, serde_json::Error> {
215-
serde_json::to_string(self)
216-
}
217-
218190
/// Creates a new Card object with the latest version and the specified unique identifier.
219191
pub fn new_with_latest_version(uid: &str) -> Self {
220192
Self {
@@ -244,7 +216,7 @@ impl Card {
244216
};
245217
}
246218

247-
/// Get available languages in the Card object.
219+
/// Get available languages from the [`Card::localizations`]
248220
pub fn get_available_languages(&self) -> Vec<String> {
249221
match &self.localizations {
250222
Some(localizations_map) => localizations_map.keys().cloned().collect(),
@@ -276,6 +248,39 @@ impl Card {
276248
}
277249
}
278250

251+
impl FromStr for Card {
252+
type Err = serde_json::Error;
253+
254+
fn from_str(s: &str) -> Result<Self, Self::Err> {
255+
serde_json::from_str(s)
256+
}
257+
}
258+
259+
impl TryFrom<&[u8]> for Card {
260+
type Error = serde_json::Error;
261+
262+
fn try_from(slice: &[u8]) -> Result<Self, Self::Error> {
263+
serde_json::from_slice(slice)
264+
}
265+
}
266+
267+
impl TryFrom<Value> for Card {
268+
type Error = String;
269+
270+
fn try_from(value: Value) -> Result<Self, Self::Error> {
271+
let card: Card = serde_json::from_value(value.clone()).map_err(|e| e.to_string())?;
272+
Ok(card)
273+
}
274+
}
275+
276+
impl TryFrom<Card> for String {
277+
type Error = serde_json::Error;
278+
279+
fn try_from(card: Card) -> Result<Self, Self::Error> {
280+
serde_json::to_string(&card)
281+
}
282+
}
283+
279284
/// Localize the Card object with jsonptr
280285
#[cfg(feature = "jsonptr")]
281286
fn localize_card(

src/lib.rs

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,26 +11,54 @@
1111
//! use jscontact::Card;
1212
//! use serde_json;
1313
//!
14-
//! let json = serde_json::json!({
14+
//! let json_value = serde_json::json!({
1515
//! "@type": "Card",
1616
//! "version": "1.0",
1717
//! "uid": "1234"
1818
//! });
19-
//! let card = Card::from_value(json).unwrap();
20-
//!
21-
//! let str = card.serialize_str().unwrap();
22-
//!
23-
//! let card = Card::try_from_str(str).unwrap();
19+
//! let card_deserialized: Card = Card::try_from(json_value).unwrap(); // deserialize from serde::Value
20+
//! let card_string: String = String::try_from(card_deserialized.clone()).unwrap(); // serialize to String
21+
//! let card: Card = card_string.parse().unwrap(); // deserialize with parse()
22+
//! assert_eq!(card_deserialized, card);
2423
//! ```
2524
//!
2625
//! Simple creation example:
2726
//! ```rust
28-
//! use jscontact::{Card, CardKind, Name, NameComponent, NameComponentKind};
27+
//! use jscontact::{Card, CardKind, CardVersion, Name, NameComponent, NameComponentKind};
2928
//! use serde_json;
3029
//!
31-
//! let mut card = Card::new_with_latest_version("my:uri");
30+
//! let mut card = Card::new(CardVersion::OneDotZero, "my:uri");
3231
//! card.kind = Some(CardKind::Individual);
33-
//! let json = serde_json::to_string(&card).unwrap();
32+
//! let json = serde_json::to_string(&card).unwrap(); // serialize with serde
33+
//! ```
34+
//!
35+
//! Get localized Card:
36+
//! ```rust
37+
//! use jscontact::{Card, CardVersion, Name};
38+
//! use std::collections::HashMap;
39+
//! use serde_json::Value;
40+
//!
41+
//! // create a card
42+
//! let mut card = Card::new(CardVersion::OneDotZero, "my:uri");
43+
//! let mut name = Name::default();
44+
//! name.full = Some("John".to_string());
45+
//! card.name = Some(name);
46+
//!
47+
//! // add localization
48+
//! let mut translations: HashMap<String, Value> = HashMap::new();
49+
//! let mut name_en = Name::default();
50+
//! name_en.full = Some("Johny".to_string());
51+
//! translations.insert(
52+
//! "name".to_string(),
53+
//! serde_json::to_value(name_en).expect("Failed to serialize name"),
54+
//! );
55+
//! card.add_localization("en", translations);
56+
//!
57+
//! // use localized card
58+
//! let langs = card.get_available_languages();
59+
//! assert_eq!(langs, vec!["en"]);
60+
//! let localized = card.get_localized(&langs[0]).unwrap();
61+
//! assert_eq!(localized.name.unwrap().full.unwrap(), "Johny");
3462
//! ```
3563
3664
#![deny(

tests/tests.rs

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
mod test {
2+
use jscontact::Card;
3+
use serde_json::Value;
4+
5+
#[test]
6+
fn test_usage_1() {
7+
let json = r#"
8+
{
9+
"@type": "Card",
10+
"version": "1.0",
11+
"uid": "22B2C7DF-9120-4969-8460-05956FE6B065",
12+
"name": {
13+
"components": [{
14+
"kind": "given",
15+
"value": "John",
16+
"phonetic": "/ˈdʒɑːn/"
17+
}, {
18+
"kind": "surname",
19+
"value": "Smith",
20+
"phonetic": "/smɪθ/"
21+
}],
22+
"phoneticSystem": "ipa"
23+
}
24+
}"#;
25+
let card: Card = serde_json::from_str(json).unwrap();
26+
27+
let card_2 = json.parse().unwrap();
28+
29+
assert_eq!(card, card_2);
30+
}
31+
32+
#[test]
33+
fn test_usage_2() {
34+
let json = r#"
35+
{
36+
"@type": "Card",
37+
"version": "1.0",
38+
"uid": "22B2C7DF-9120-4969-8460-05956FE6B065",
39+
"name": {
40+
"components": [{
41+
"kind": "given",
42+
"value": "John",
43+
"phonetic": "/ˈdʒɑːn/"
44+
}, {
45+
"kind": "surname",
46+
"value": "Smith",
47+
"phonetic": "/smɪθ/"
48+
}],
49+
"phoneticSystem": "ipa"
50+
}
51+
}"#;
52+
let card_value: Value = serde_json::from_str(json).unwrap();
53+
let card: Card = serde_json::from_value(card_value.clone()).unwrap();
54+
55+
let card_into: Card = card_value.try_into().unwrap();
56+
assert_eq!(card, card_into);
57+
}
58+
59+
#[test]
60+
fn test_localized() {
61+
use jscontact::{Card, CardVersion, Name};
62+
use std::collections::HashMap;
63+
64+
let mut card = Card::new(CardVersion::OneDotZero, "my:uri");
65+
let mut name = Name::default();
66+
name.full = Some("John".to_string());
67+
card.name = Some(name);
68+
69+
let mut translations: HashMap<String, Value> = HashMap::new();
70+
let mut name_en = Name::default();
71+
name_en.full = Some("Johny".to_string());
72+
translations.insert(
73+
"name".to_string(),
74+
serde_json::to_value(name_en).expect("Failed to serialize name"),
75+
);
76+
card.add_localization("en", translations);
77+
78+
let langs = card.get_available_languages();
79+
assert_eq!(langs, vec!["en"]);
80+
let localized = card.get_localized(&langs[0]).unwrap();
81+
assert_eq!(localized.name.unwrap().full.unwrap(), "Johny");
82+
}
83+
}

0 commit comments

Comments
 (0)