From 25a32506674558adf56ab41c3b5f3b7bd679a0bd Mon Sep 17 00:00:00 2001 From: Titouan Rigoudy Date: Thu, 4 Jan 2018 18:15:41 -0500 Subject: [PATCH] Implement ProtoEncode for RoomJoinResponse. --- src/proto/codec.rs | 15 +++++- src/proto/server/response.rs | 88 ++++++++++++++++++++++++++++++++++++ src/user.rs | 23 ++++++++++ 3 files changed, 125 insertions(+), 1 deletion(-) diff --git a/src/proto/codec.rs b/src/proto/codec.rs index eed20b8..f91bb3a 100644 --- a/src/proto/codec.rs +++ b/src/proto/codec.rs @@ -308,19 +308,32 @@ impl ProtoDecode for String { } } +// It would be nice to use AsRef for the following stringy types instead +// of having to spell them out, but trying that fails because E0119: +// "upstream crates may add new impl of trait `core::convert::AsRef` for +// type `bool` in future versions". +// We could probably work around this with more complex type logic (e.g. +// wrapping primitive types in a newtype for which we implement +// Proto{De,En}code) but it is not really worth the hassle. + impl ProtoEncode for str { fn encode(&self, encoder: &mut ProtoEncoder) -> io::Result<()> { encoder.encode_string(self) } } -// Apparently deref coercion does not work for trait methods. impl ProtoEncode for String { fn encode(&self, encoder: &mut ProtoEncoder) -> io::Result<()> { encoder.encode_string(self) } } +impl<'a> ProtoEncode for &'a String { + fn encode(&self, encoder: &mut ProtoEncoder) -> io::Result<()> { + encoder.encode_string(*self) + } +} + impl ProtoDecode for Vec { fn decode(decoder: &mut ProtoDecoder) -> Result { decoder.decode_vec::() diff --git a/src/proto/server/response.rs b/src/proto/server/response.rs index 5e87369..2c167de 100644 --- a/src/proto/server/response.rs +++ b/src/proto/server/response.rs @@ -611,6 +611,94 @@ impl RoomJoinResponse { } } +// This struct is defined to enable decoding a vector of such values for +// `RoomJoinResponse`, but its data is inlined in the `User` struct. +// For details about individual fields, see said `User` struct. +#[derive(Debug, Eq, PartialEq)] +struct UserInfo { + average_speed: u32, + num_downloads: u32, + unknown: u32, + num_files: u32, + num_folders: u32, +} + +impl<'a> From<&'a user::User> for UserInfo { + fn from(user: &'a user::User) -> Self { + Self { + average_speed: user.average_speed as u32, + num_downloads: user.num_downloads as u32, + unknown: user.unknown as u32, + num_files: user.num_files as u32, + num_folders: user.num_folders as u32, + } + } +} + +impl ProtoEncode for UserInfo { + fn encode(&self, encoder: &mut ProtoEncoder) -> Result<(), io::Error> { + encoder.encode_u32(self.average_speed)?; + encoder.encode_u32(self.num_downloads)?; + encoder.encode_u32(self.unknown)?; + encoder.encode_u32(self.num_files)?; + encoder.encode_u32(self.num_folders) + } +} + +impl ProtoDecode for UserInfo { + fn decode(decoder: &mut ProtoDecoder) -> Result { + let average_speed = decoder.decode_u32()?; + let num_downloads = decoder.decode_u32()?; + let unknown = decoder.decode_u32()?; + let num_files = decoder.decode_u32()?; + let num_folders = decoder.decode_u32()?; + Ok(Self { + average_speed: average_speed, + num_downloads: num_downloads, + unknown: unknown, + num_files: num_files, + num_folders: num_folders, + }) + } +} + +impl ProtoEncode for RoomJoinResponse { + fn encode(&self, encoder: &mut ProtoEncoder) -> Result<(), io::Error> { + let mut user_names = vec![]; + let mut user_statuses = vec![]; + let mut user_infos = vec![]; + let mut user_free_slots = vec![]; + let mut user_countries = vec![]; + for &(ref user_name, ref user) in &self.users { + user_names.push(user_name); + user_statuses.push(user.status); + user_infos.push(UserInfo::from(user)); + user_free_slots.push(user.num_free_slots as u32); + user_countries.push(&user.country); + } + + encoder.encode_string(&self.room_name)?; + encoder.encode_vec(&user_names)?; + encoder.encode_vec(&user_statuses)?; + encoder.encode_vec(&user_infos)?; + encoder.encode_vec(&user_free_slots)?; + encoder.encode_vec(&user_countries)?; + + if let &Some(ref owner) = &self.owner { + encoder.encode_string(owner)?; + encoder.encode_vec(&self.operators)?; + } + + Ok(()) + } +} + +impl ProtoDecode for RoomJoinResponse { + fn decode(decoder: &mut ProtoDecoder) -> Result { + unimplemented!(); + } +} + /*============* * ROOM LEAVE * *============*/ diff --git a/src/user.rs b/src/user.rs index a1fd7c1..922f51a 100644 --- a/src/user.rs +++ b/src/user.rs @@ -44,6 +44,29 @@ impl proto::WriteToPacket for Status { } } +impl proto::ProtoEncode for Status { + fn encode(&self, encoder: &mut proto::ProtoEncoder) -> io::Result<()> { + let value = match *self { + Status::Offline => STATUS_OFFLINE, + Status::Away => STATUS_AWAY, + Status::Online => STATUS_ONLINE, + }; + encoder.encode_u32(value) + } +} + +impl proto::ProtoDecode for Status { + fn decode(decoder: &mut proto::ProtoDecoder) -> Result { + let value = decoder.decode_u32()?; + match value { + STATUS_OFFLINE => Ok(Status::Offline), + STATUS_AWAY => Ok(Status::Away), + STATUS_ONLINE => Ok(Status::Online), + _ => Err(proto::DecodeError::InvalidUserStatusError(value)), + } + } +} + /// This structure contains the last known information about a fellow user. /// It does not store the name, as that is stored implicitly as the key in the /// user hash table.