Skip to content

Commit f5781d4

Browse files
alexandruagandreeaflorescu
authored andcommitted
NetworkInterfaceBody: reworked de/serialization
The de/serialization of this structure previously relied on two local helper functions to handle the guest_mac: Option<MacAddr> field. However, this led to buggy behaviour, as the guest_mac = None case was not handled properly. We eliminate the local functions, and rely on the implementation of Serialize and Deserialize for MacAddr instead. Also added one more unit test function. Signed-off-by: Alexandru Agache <[email protected]>
1 parent fa9aaef commit f5781d4

File tree

1 file changed

+37
-34
lines changed
  • api_server/src/request/sync

1 file changed

+37
-34
lines changed

api_server/src/request/sync/net.rs

Lines changed: 37 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,40 +2,9 @@ use std::result;
22

33
use futures::sync::oneshot;
44

5-
use request::ParsedRequest;
6-
use serde::de::{self, Deserialize, Deserializer};
7-
use serde::ser::{Serialize, Serializer};
8-
95
use super::{DeviceState, SyncRequest};
106
use net_util::MacAddr;
11-
12-
// used to serialize an Option<MacAddr>
13-
fn mac_serialize_with<S>(what: &Option<MacAddr>, serializer: S) -> result::Result<S::Ok, S::Error>
14-
where
15-
S: Serializer,
16-
{
17-
if let Some(ref mac) = *what {
18-
mac.to_string().serialize(serializer)
19-
} else {
20-
"".serialize(serializer)
21-
}
22-
}
23-
24-
// used to deserialize an Option<MacAddr>
25-
fn mac_deserialize_with<'de, D>(deserializer: D) -> result::Result<Option<MacAddr>, D::Error>
26-
where
27-
D: Deserializer<'de>,
28-
{
29-
// TODO: is there a more efficient way around this? (i.e. deserialize to a slice
30-
// instead of a String?!)
31-
if let Some(ref s) = Option::<String>::deserialize(deserializer)? {
32-
MacAddr::parse_str(s)
33-
.map(|mac_addr| Some(mac_addr))
34-
.map_err(|_| de::Error::custom("invalid MAC address."))
35-
} else {
36-
Ok(None)
37-
}
38-
}
7+
use request::ParsedRequest;
398

409
// This struct represents the strongly typed equivalent of the json body from net iface
4110
// related requests.
@@ -44,8 +13,7 @@ pub struct NetworkInterfaceBody {
4413
pub iface_id: String,
4514
pub state: DeviceState,
4615
pub host_dev_name: String,
47-
#[serde(serialize_with = "self::mac_serialize_with",
48-
deserialize_with = "self::mac_deserialize_with")]
16+
#[serde(skip_serializing_if = "Option::is_none")]
4917
pub guest_mac: Option<MacAddr>,
5018
}
5119

@@ -68,6 +36,7 @@ impl NetworkInterfaceBody {
6836
#[cfg(test)]
6937
mod tests {
7038
use super::*;
39+
use serde_json;
7140

7241
#[test]
7342
fn test_netif_into_parsed_request() {
@@ -90,4 +59,38 @@ mod tests {
9059
)))
9160
);
9261
}
62+
63+
#[test]
64+
fn test_network_interface_body_serialization_and_deserialization() {
65+
let netif = NetworkInterfaceBody {
66+
iface_id: String::from("foo"),
67+
state: DeviceState::Attached,
68+
host_dev_name: String::from("bar"),
69+
guest_mac: Some(MacAddr::parse_str("12:34:56:78:9A:BC").unwrap()),
70+
};
71+
72+
// This is the json encoding of the netif variable.
73+
let jstr = r#"{
74+
"iface_id": "foo",
75+
"host_dev_name": "bar",
76+
"state": "Attached",
77+
"guest_mac": "12:34:56:78:9A:bc"
78+
}"#;
79+
80+
let x = serde_json::from_str(jstr).expect("deserialization failed.");
81+
assert_eq!(netif, x);
82+
83+
let y = serde_json::to_string(&netif).expect("serialization failed.");
84+
let z = serde_json::from_str(y.as_ref()).expect("deserialization (2) failed.");
85+
assert_eq!(x, z);
86+
87+
// Check that guest_mac is truly optional.
88+
let jstr_no_mac = r#"{
89+
"iface_id": "foo",
90+
"host_dev_name": "bar",
91+
"state": "Attached"
92+
}"#;
93+
94+
assert!(serde_json::from_str::<NetworkInterfaceBody>(jstr_no_mac).is_ok())
95+
}
9396
}

0 commit comments

Comments
 (0)