Re-rustfmt ruma-events

This commit is contained in:
Jonas Platte 2020-06-10 22:17:59 +02:00
parent f304c04d1d
commit fbf0deacfe
No known key found for this signature in database
GPG Key ID: 7D261D771D915378
15 changed files with 56 additions and 188 deletions

View File

@ -58,13 +58,7 @@ mod tests {
#[test] #[test]
fn serialize_and_deserialize_from_display_form() { fn serialize_and_deserialize_from_display_form() {
serde_json_eq(Algorithm::MegolmV1AesSha2, json!("m.megolm.v1.aes-sha2")); serde_json_eq(Algorithm::MegolmV1AesSha2, json!("m.megolm.v1.aes-sha2"));
serde_json_eq( serde_json_eq(Algorithm::OlmV1Curve25519AesSha2, json!("m.olm.v1.curve25519-aes-sha2"));
Algorithm::OlmV1Curve25519AesSha2, serde_json_eq(Algorithm::Custom("io.ruma.test".to_string()), json!("io.ruma.test"));
json!("m.olm.v1.curve25519-aes-sha2"),
);
serde_json_eq(
Algorithm::Custom("io.ruma.test".to_string()),
json!("io.ruma.test"),
);
} }
} }

View File

@ -66,10 +66,7 @@ mod tests {
#[test] #[test]
fn deserialization() { fn deserialization() {
let alice = UserId::new("ruma.io").unwrap(); let alice = UserId::new("ruma.io").unwrap();
let rooms = vec![ let rooms = vec![RoomId::new("ruma.io").unwrap(), RoomId::new("ruma.io").unwrap()];
RoomId::new("ruma.io").unwrap(),
RoomId::new("ruma.io").unwrap(),
];
let json_data = json!({ let json_data = json!({
"content": { "content": {
@ -78,10 +75,8 @@ mod tests {
"type": "m.direct" "type": "m.direct"
}); });
let event: DirectEvent = from_json_value::<EventJson<_>>(json_data) let event: DirectEvent =
.unwrap() from_json_value::<EventJson<_>>(json_data).unwrap().deserialize().unwrap();
.deserialize()
.unwrap();
let direct_rooms = event.content.get(&alice).unwrap(); let direct_rooms = event.content.get(&alice).unwrap();
assert!(direct_rooms.contains(&rooms[0])); assert!(direct_rooms.contains(&rooms[0]));

View File

@ -47,9 +47,7 @@ mod tests {
#[test] #[test]
fn serialization() { fn serialization() {
let dummy_event = DummyEvent { let dummy_event = DummyEvent { content: DummyEventContent(Empty) };
content: DummyEventContent(Empty),
};
let actual = to_json_value(dummy_event).unwrap(); let actual = to_json_value(dummy_event).unwrap();
let expected = json!({ let expected = json!({
@ -67,9 +65,6 @@ mod tests {
"type": "m.dummy" "type": "m.dummy"
}); });
assert!(from_json_value::<EventJson<DummyEvent>>(json) assert!(from_json_value::<EventJson<DummyEvent>>(json).unwrap().deserialize().is_ok());
.unwrap()
.deserialize()
.is_ok());
} }
} }

View File

@ -271,64 +271,34 @@ mod tests {
serde_json_eq(EventType::Dummy, json!("m.dummy")); serde_json_eq(EventType::Dummy, json!("m.dummy"));
serde_json_eq(EventType::ForwardedRoomKey, json!("m.forwarded_room_key")); serde_json_eq(EventType::ForwardedRoomKey, json!("m.forwarded_room_key"));
serde_json_eq(EventType::FullyRead, json!("m.fully_read")); serde_json_eq(EventType::FullyRead, json!("m.fully_read"));
serde_json_eq( serde_json_eq(EventType::KeyVerificationAccept, json!("m.key.verification.accept"));
EventType::KeyVerificationAccept, serde_json_eq(EventType::KeyVerificationCancel, json!("m.key.verification.cancel"));
json!("m.key.verification.accept"), serde_json_eq(EventType::KeyVerificationKey, json!("m.key.verification.key"));
); serde_json_eq(EventType::KeyVerificationMac, json!("m.key.verification.mac"));
serde_json_eq( serde_json_eq(EventType::KeyVerificationRequest, json!("m.key.verification.request"));
EventType::KeyVerificationCancel, serde_json_eq(EventType::KeyVerificationStart, json!("m.key.verification.start"));
json!("m.key.verification.cancel"),
);
serde_json_eq(
EventType::KeyVerificationKey,
json!("m.key.verification.key"),
);
serde_json_eq(
EventType::KeyVerificationMac,
json!("m.key.verification.mac"),
);
serde_json_eq(
EventType::KeyVerificationRequest,
json!("m.key.verification.request"),
);
serde_json_eq(
EventType::KeyVerificationStart,
json!("m.key.verification.start"),
);
serde_json_eq(EventType::IgnoredUserList, json!("m.ignored_user_list")); serde_json_eq(EventType::IgnoredUserList, json!("m.ignored_user_list"));
serde_json_eq(EventType::Presence, json!("m.presence")); serde_json_eq(EventType::Presence, json!("m.presence"));
serde_json_eq(EventType::PushRules, json!("m.push_rules")); serde_json_eq(EventType::PushRules, json!("m.push_rules"));
serde_json_eq(EventType::Receipt, json!("m.receipt")); serde_json_eq(EventType::Receipt, json!("m.receipt"));
serde_json_eq(EventType::RoomAliases, json!("m.room.aliases")); serde_json_eq(EventType::RoomAliases, json!("m.room.aliases"));
serde_json_eq(EventType::RoomAvatar, json!("m.room.avatar")); serde_json_eq(EventType::RoomAvatar, json!("m.room.avatar"));
serde_json_eq( serde_json_eq(EventType::RoomCanonicalAlias, json!("m.room.canonical_alias"));
EventType::RoomCanonicalAlias,
json!("m.room.canonical_alias"),
);
serde_json_eq(EventType::RoomCreate, json!("m.room.create")); serde_json_eq(EventType::RoomCreate, json!("m.room.create"));
serde_json_eq(EventType::RoomEncrypted, json!("m.room.encrypted")); serde_json_eq(EventType::RoomEncrypted, json!("m.room.encrypted"));
serde_json_eq(EventType::RoomEncryption, json!("m.room.encryption")); serde_json_eq(EventType::RoomEncryption, json!("m.room.encryption"));
serde_json_eq(EventType::RoomGuestAccess, json!("m.room.guest_access")); serde_json_eq(EventType::RoomGuestAccess, json!("m.room.guest_access"));
serde_json_eq( serde_json_eq(EventType::RoomHistoryVisibility, json!("m.room.history_visibility"));
EventType::RoomHistoryVisibility,
json!("m.room.history_visibility"),
);
serde_json_eq(EventType::RoomJoinRules, json!("m.room.join_rules")); serde_json_eq(EventType::RoomJoinRules, json!("m.room.join_rules"));
serde_json_eq(EventType::RoomMember, json!("m.room.member")); serde_json_eq(EventType::RoomMember, json!("m.room.member"));
serde_json_eq(EventType::RoomMessage, json!("m.room.message")); serde_json_eq(EventType::RoomMessage, json!("m.room.message"));
serde_json_eq( serde_json_eq(EventType::RoomMessageFeedback, json!("m.room.message.feedback"));
EventType::RoomMessageFeedback,
json!("m.room.message.feedback"),
);
serde_json_eq(EventType::RoomName, json!("m.room.name")); serde_json_eq(EventType::RoomName, json!("m.room.name"));
serde_json_eq(EventType::RoomPinnedEvents, json!("m.room.pinned_events")); serde_json_eq(EventType::RoomPinnedEvents, json!("m.room.pinned_events"));
serde_json_eq(EventType::RoomPowerLevels, json!("m.room.power_levels")); serde_json_eq(EventType::RoomPowerLevels, json!("m.room.power_levels"));
serde_json_eq(EventType::RoomRedaction, json!("m.room.redaction")); serde_json_eq(EventType::RoomRedaction, json!("m.room.redaction"));
serde_json_eq(EventType::RoomServerAcl, json!("m.room.server_acl")); serde_json_eq(EventType::RoomServerAcl, json!("m.room.server_acl"));
serde_json_eq( serde_json_eq(EventType::RoomThirdPartyInvite, json!("m.room.third_party_invite"));
EventType::RoomThirdPartyInvite,
json!("m.room.third_party_invite"),
);
serde_json_eq(EventType::RoomTombstone, json!("m.room.tombstone")); serde_json_eq(EventType::RoomTombstone, json!("m.room.tombstone"));
serde_json_eq(EventType::RoomTopic, json!("m.room.topic")); serde_json_eq(EventType::RoomTopic, json!("m.room.topic"));
serde_json_eq(EventType::RoomKey, json!("m.room_key")); serde_json_eq(EventType::RoomKey, json!("m.room_key"));
@ -336,9 +306,6 @@ mod tests {
serde_json_eq(EventType::Sticker, json!("m.sticker")); serde_json_eq(EventType::Sticker, json!("m.sticker"));
serde_json_eq(EventType::Tag, json!("m.tag")); serde_json_eq(EventType::Tag, json!("m.tag"));
serde_json_eq(EventType::Typing, json!("m.typing")); serde_json_eq(EventType::Typing, json!("m.typing"));
serde_json_eq( serde_json_eq(EventType::Custom("io.ruma.test".to_string()), json!("io.ruma.test"));
EventType::Custom("io.ruma.test".to_string()),
json!("io.ruma.test"),
);
} }
} }

View File

@ -25,10 +25,7 @@ pub struct EventJson<T> {
impl<T> EventJson<T> { impl<T> EventJson<T> {
fn new(json: Box<RawValue>) -> Self { fn new(json: Box<RawValue>) -> Self {
Self { Self { json, _ev: PhantomData }
json,
_ev: PhantomData,
}
} }
/// Create an `EventJson` from a boxed `RawValue`. /// Create an `EventJson` from a boxed `RawValue`.
@ -55,10 +52,9 @@ where
pub fn deserialize(&self) -> Result<T, InvalidEvent> { pub fn deserialize(&self) -> Result<T, InvalidEvent> {
match serde_json::from_str(self.json.get()) { match serde_json::from_str(self.json.get()) {
Ok(value) => Ok(value), Ok(value) => Ok(value),
Err(err) => Err(InvalidEvent { Err(err) => {
message: err.to_string(), Err(InvalidEvent { message: err.to_string(), kind: InvalidEventKind::Validation })
kind: InvalidEventKind::Validation, }
}),
} }
} }
} }
@ -69,10 +65,8 @@ where
{ {
/// Try to deserialize the JSON as event content /// Try to deserialize the JSON as event content
pub fn deserialize_content(self, event_type: &str) -> Result<T, InvalidEvent> { pub fn deserialize_content(self, event_type: &str) -> Result<T, InvalidEvent> {
T::from_parts(event_type, self.json).map_err(|err| InvalidEvent { T::from_parts(event_type, self.json)
message: err, .map_err(|err| InvalidEvent { message: err, kind: InvalidEventKind::Deserialization })
kind: InvalidEventKind::Deserialization,
})
} }
} }

View File

@ -139,10 +139,7 @@ mod tests {
#[test] #[test]
fn cancel_codes_deserialize_from_display_form() { fn cancel_codes_deserialize_from_display_form() {
assert_eq!( assert_eq!(from_json_value::<CancelCode>(json!("m.user")).unwrap(), CancelCode::User);
from_json_value::<CancelCode>(json!("m.user")).unwrap(),
CancelCode::User
);
} }
#[test] #[test]

View File

@ -105,10 +105,7 @@ impl MSasV1Content {
/// `MessageAuthenticationCode::HkdfHmacSha256`. /// `MessageAuthenticationCode::HkdfHmacSha256`.
/// * `short_authentication_string` does not include `ShortAuthenticationString::Decimal`. /// * `short_authentication_string` does not include `ShortAuthenticationString::Decimal`.
pub fn new(options: MSasV1ContentOptions) -> Result<Self, InvalidInput> { pub fn new(options: MSasV1ContentOptions) -> Result<Self, InvalidInput> {
if !options if !options.key_agreement_protocols.contains(&KeyAgreementProtocol::Curve25519) {
.key_agreement_protocols
.contains(&KeyAgreementProtocol::Curve25519)
{
return Err(InvalidInput("`key_agreement_protocols` must contain at least `KeyAgreementProtocol::Curve25519`".to_string())); return Err(InvalidInput("`key_agreement_protocols` must contain at least `KeyAgreementProtocol::Curve25519`".to_string()));
} }
@ -125,10 +122,7 @@ impl MSasV1Content {
return Err(InvalidInput("`message_authentication_codes` must contain at least `MessageAuthenticationCode::HkdfHmacSha256`".to_string())); return Err(InvalidInput("`message_authentication_codes` must contain at least `MessageAuthenticationCode::HkdfHmacSha256`".to_string()));
} }
if !options if !options.short_authentication_string.contains(&ShortAuthenticationString::Decimal) {
.short_authentication_string
.contains(&ShortAuthenticationString::Decimal)
{
return Err(InvalidInput("`short_authentication_string` must contain at least `ShortAuthenticationString::Decimal`".to_string())); return Err(InvalidInput("`short_authentication_string` must contain at least `ShortAuthenticationString::Decimal`".to_string()));
} }
@ -232,9 +226,7 @@ mod tests {
.unwrap(), .unwrap(),
); );
let key_verification_start = StartEvent { let key_verification_start = StartEvent { content: key_verification_start_content };
content: key_verification_start_content,
};
let json_data = json!({ let json_data = json!({
"content": { "content": {

View File

@ -189,10 +189,7 @@ mod tests {
"kind": "room_member_count" "kind": "room_member_count"
}); });
assert_eq!( assert_eq!(
to_json_value(&PushCondition::RoomMemberCount { to_json_value(&PushCondition::RoomMemberCount { is: "2".to_string() }).unwrap(),
is: "2".to_string(),
})
.unwrap(),
json_data json_data
); );
} }
@ -205,10 +202,8 @@ mod tests {
}); });
assert_eq!( assert_eq!(
json_data, json_data,
to_json_value(&PushCondition::SenderNotificationPermission { to_json_value(&PushCondition::SenderNotificationPermission { key: "room".to_string() })
key: "room".to_string(), .unwrap()
})
.unwrap()
); );
} }
@ -456,9 +451,7 @@ mod tests {
"type": "m.push_rules" "type": "m.push_rules"
}); });
let _ = from_json_value::<EventJson<PushRulesEvent>>(json_data) let _ =
.unwrap() from_json_value::<EventJson<PushRulesEvent>>(json_data).unwrap().deserialize().unwrap();
.deserialize()
.unwrap();
} }
} }

View File

@ -92,10 +92,7 @@ mod tests {
"session_id": "session_id" "session_id": "session_id"
}); });
assert_eq!( assert_eq!(to_json_value(&key_verification_start_content).unwrap(), json_data);
to_json_value(&key_verification_start_content).unwrap(),
json_data
);
} }
#[test] #[test]

View File

@ -384,11 +384,7 @@ pub struct InReplyTo {
impl TextMessageEventContent { impl TextMessageEventContent {
/// A convenience constructor to create a plain text message /// A convenience constructor to create a plain text message
pub fn new_plain(body: impl Into<String>) -> TextMessageEventContent { pub fn new_plain(body: impl Into<String>) -> TextMessageEventContent {
TextMessageEventContent { TextMessageEventContent { body: body.into(), formatted: None, relates_to: None }
body: body.into(),
formatted: None,
relates_to: None,
}
} }
} }

View File

@ -27,9 +27,7 @@ impl NameEventContent {
match name.len() { match name.len() {
0 => Ok(Self { name: None }), 0 => Ok(Self { name: None }),
1..=255 => Ok(Self { name: Some(name) }), 1..=255 => Ok(Self { name: Some(name) }),
_ => Err(InvalidInput( _ => Err(InvalidInput("a room name cannot be more than 255 bytes".to_string())),
"a room name cannot be more than 255 bytes".to_string(),
)),
} }
} }
@ -50,9 +48,7 @@ where
Some(name) => match name.len() { Some(name) => match name.len() {
0 => Ok(None), 0 => Ok(None),
1..=255 => Ok(Some(name)), 1..=255 => Ok(Some(name)),
_ => Err(D::Error::custom( _ => Err(D::Error::custom("a room name cannot be more than 255 bytes")),
"a room name cannot be more than 255 bytes",
)),
}, },
None => Ok(None), None => Ok(None),
} }
@ -78,9 +74,7 @@ mod tests {
#[test] #[test]
fn serialization_with_optional_fields_as_none() { fn serialization_with_optional_fields_as_none() {
let name_event = StateEvent { let name_event = StateEvent {
content: NameEventContent { content: NameEventContent { name: Some("The room name".to_string()) },
name: Some("The room name".to_string()),
},
event_id: EventId::try_from("$h29iv0s8:example.com").unwrap(), event_id: EventId::try_from("$h29iv0s8:example.com").unwrap(),
origin_server_ts: UNIX_EPOCH + Duration::from_millis(1), origin_server_ts: UNIX_EPOCH + Duration::from_millis(1),
prev_content: None, prev_content: None,
@ -109,21 +103,14 @@ mod tests {
#[test] #[test]
fn serialization_with_all_fields() { fn serialization_with_all_fields() {
let name_event = StateEvent { let name_event = StateEvent {
content: NameEventContent { content: NameEventContent { name: Some("The room name".to_string()) },
name: Some("The room name".to_string()),
},
event_id: EventId::try_from("$h29iv0s8:example.com").unwrap(), event_id: EventId::try_from("$h29iv0s8:example.com").unwrap(),
origin_server_ts: UNIX_EPOCH + Duration::from_millis(1), origin_server_ts: UNIX_EPOCH + Duration::from_millis(1),
prev_content: Some(NameEventContent { prev_content: Some(NameEventContent { name: Some("The old name".to_string()) }),
name: Some("The old name".to_string()),
}),
room_id: RoomId::try_from("!n8f893n9:example.com").unwrap(), room_id: RoomId::try_from("!n8f893n9:example.com").unwrap(),
sender: UserId::try_from("@carl:example.com").unwrap(), sender: UserId::try_from("@carl:example.com").unwrap(),
state_key: "".to_string(), state_key: "".to_string(),
unsigned: UnsignedData { unsigned: UnsignedData { age: Some(Int::from(100)), ..UnsignedData::default() },
age: Some(Int::from(100)),
..UnsignedData::default()
},
}; };
let actual = to_json_value(&name_event).unwrap(); let actual = to_json_value(&name_event).unwrap();
@ -185,10 +172,7 @@ mod tests {
fn json_with_empty_name_creates_content_as_none() { fn json_with_empty_name_creates_content_as_none() {
let long_content_json = json!({ "name": "" }); let long_content_json = json!({ "name": "" });
let from_raw: EventJson<NameEventContent> = from_json_value(long_content_json).unwrap(); let from_raw: EventJson<NameEventContent> = from_json_value(long_content_json).unwrap();
assert_matches!( assert_matches!(from_raw.deserialize().unwrap(), NameEventContent { name: None });
from_raw.deserialize().unwrap(),
NameEventContent { name: None }
);
} }
#[test] #[test]

View File

@ -17,10 +17,7 @@ pub type PowerLevelsEvent = StateEvent<PowerLevelsEventContent>;
#[ruma_event(type = "m.room.power_levels")] #[ruma_event(type = "m.room.power_levels")]
pub struct PowerLevelsEventContent { pub struct PowerLevelsEventContent {
/// The level required to ban a user. /// The level required to ban a user.
#[serde( #[serde(default = "default_power_level", skip_serializing_if = "is_default_power_level")]
default = "default_power_level",
skip_serializing_if = "is_default_power_level"
)]
pub ban: Int, pub ban: Int,
/// The level required to send specific event types. /// The level required to send specific event types.
@ -34,31 +31,19 @@ pub struct PowerLevelsEventContent {
pub events_default: Int, pub events_default: Int,
/// The level required to invite a user. /// The level required to invite a user.
#[serde( #[serde(default = "default_power_level", skip_serializing_if = "is_default_power_level")]
default = "default_power_level",
skip_serializing_if = "is_default_power_level"
)]
pub invite: Int, pub invite: Int,
/// The level required to kick a user. /// The level required to kick a user.
#[serde( #[serde(default = "default_power_level", skip_serializing_if = "is_default_power_level")]
default = "default_power_level",
skip_serializing_if = "is_default_power_level"
)]
pub kick: Int, pub kick: Int,
/// The level required to redact an event. /// The level required to redact an event.
#[serde( #[serde(default = "default_power_level", skip_serializing_if = "is_default_power_level")]
default = "default_power_level",
skip_serializing_if = "is_default_power_level"
)]
pub redact: Int, pub redact: Int,
/// The default level required to send state events. /// The default level required to send state events.
#[serde( #[serde(default = "default_power_level", skip_serializing_if = "is_default_power_level")]
default = "default_power_level",
skip_serializing_if = "is_default_power_level"
)]
pub state_default: Int, pub state_default: Int,
/// The power levels for specific users. /// The power levels for specific users.
@ -107,9 +92,7 @@ pub struct NotificationPowerLevels {
impl Default for NotificationPowerLevels { impl Default for NotificationPowerLevels {
fn default() -> Self { fn default() -> Self {
Self { Self { room: default_power_level() }
room: default_power_level(),
}
} }
} }
@ -198,9 +181,7 @@ mod tests {
user.clone() => Int::from(23) user.clone() => Int::from(23)
}, },
users_default: Int::from(23), users_default: Int::from(23),
notifications: NotificationPowerLevels { notifications: NotificationPowerLevels { room: Int::from(23) },
room: Int::from(23),
},
}, },
event_id: EventId::try_from("$h29iv0s8:example.com").unwrap(), event_id: EventId::try_from("$h29iv0s8:example.com").unwrap(),
origin_server_ts: UNIX_EPOCH + Duration::from_millis(1), origin_server_ts: UNIX_EPOCH + Duration::from_millis(1),
@ -219,15 +200,10 @@ mod tests {
user.clone() => Int::from(42) user.clone() => Int::from(42)
}, },
users_default: Int::from(42), users_default: Int::from(42),
notifications: NotificationPowerLevels { notifications: NotificationPowerLevels { room: Int::from(42) },
room: Int::from(42),
},
}), }),
room_id: RoomId::try_from("!n8f893n9:example.com").unwrap(), room_id: RoomId::try_from("!n8f893n9:example.com").unwrap(),
unsigned: UnsignedData { unsigned: UnsignedData { age: Some(Int::from(100)), ..UnsignedData::default() },
age: Some(Int::from(100)),
..UnsignedData::default()
},
sender: user, sender: user,
state_key: "".to_string(), state_key: "".to_string(),
}; };

View File

@ -81,9 +81,7 @@ mod tests {
#[test] #[test]
fn serialization() { fn serialization() {
let event = RedactionEvent { let event = RedactionEvent {
content: RedactionEventContent { content: RedactionEventContent { reason: Some("redacted because".into()) },
reason: Some("redacted because".into()),
},
redacts: EventId::try_from("$h29iv0s8:example.com").unwrap(), redacts: EventId::try_from("$h29iv0s8:example.com").unwrap(),
event_id: EventId::try_from("$h29iv0s8:example.com").unwrap(), event_id: EventId::try_from("$h29iv0s8:example.com").unwrap(),
origin_server_ts: UNIX_EPOCH + Duration::from_millis(1), origin_server_ts: UNIX_EPOCH + Duration::from_millis(1),

View File

@ -17,10 +17,7 @@ pub struct ServerAclEventContent {
/// This is strongly recommended to be set to false as servers running with IP literal /// This is strongly recommended to be set to false as servers running with IP literal
/// names are strongly discouraged in order to require legitimate homeservers to be /// names are strongly discouraged in order to require legitimate homeservers to be
/// backed by a valid registered domain name. /// backed by a valid registered domain name.
#[serde( #[serde(default = "ruma_serde::default_true", skip_serializing_if = "ruma_serde::is_true")]
default = "ruma_serde::default_true",
skip_serializing_if = "ruma_serde::is_true"
)]
pub allow_ip_literals: bool, pub allow_ip_literals: bool,
/// The server names to allow in the room, excluding any port information. Wildcards may /// The server names to allow in the room, excluding any port information. Wildcards may

View File

@ -6,9 +6,7 @@ where
T: DeserializeOwned, T: DeserializeOwned,
E: serde::de::Error, E: serde::de::Error,
{ {
serde_json::from_value(value) serde_json::from_value(value).map(variant).map_err(serde_json_error_to_generic_de_error)
.map(variant)
.map_err(serde_json_error_to_generic_de_error)
} }
pub fn serde_json_error_to_generic_de_error<E: serde::de::Error>(error: serde_json::Error) -> E { pub fn serde_json_error_to_generic_de_error<E: serde::de::Error>(error: serde_json::Error) -> E {
@ -20,11 +18,6 @@ where
T: DeserializeOwned, T: DeserializeOwned,
E: serde::de::Error, E: serde::de::Error,
{ {
serde_json::from_value( serde_json::from_value(value.get(field).cloned().ok_or_else(|| E::missing_field(field))?)
value .map_err(serde_json_error_to_generic_de_error)
.get(field)
.cloned()
.ok_or_else(|| E::missing_field(field))?,
)
.map_err(serde_json_error_to_generic_de_error)
} }