Skip to content

Commit cf0fc2c

Browse files
authored
Add try/into map iterator for message ref (#9)
1 parent d74205b commit cf0fc2c

File tree

4 files changed

+59
-1
lines changed

4 files changed

+59
-1
lines changed

msgpacker/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "msgpacker"
3-
version = "0.3.0"
3+
version = "0.3.1"
44
authors = ["Victor Lopez <victor@codx.io>"]
55
categories = ["compression", "encoding", "parser-implementations"]
66
edition = "2021"

msgpacker/src/map/map_ref.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ impl<'a> MapEntryRef<'a> {
2424
&self.val
2525
}
2626

27+
pub(crate) fn into_inner(self) -> (MessageRef<'a>, MessageRef<'a>) {
28+
(self.key, self.val)
29+
}
30+
2731
/// Access the internal key and value as a tuple of references
2832
pub const fn inner(&self) -> (&MessageRef<'a>, &MessageRef<'a>) {
2933
(&self.key, &self.val)

msgpacker/src/message_ref.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,27 @@ impl<'a> MessageRef<'a> {
102102
as_value_ref!(as_map, &'a [MapEntryRef], Map);
103103
as_value_ref!(as_extension, &'a ExtensionRef, Extension);
104104

105+
/// Attempt to match every item of the message as map, and then convert it to key/value pairs
106+
pub fn try_collect_map<M, K, V>(self) -> Option<io::Result<M>>
107+
where
108+
M: FromIterator<(K, V)>,
109+
K: TryFrom<MessageRef<'a>, Error = io::Error>,
110+
V: TryFrom<MessageRef<'a>, Error = io::Error>,
111+
{
112+
let m = match self {
113+
MessageRef::Map(m) => m,
114+
_ => return None,
115+
};
116+
117+
let map = m
118+
.into_iter()
119+
.map(|entry| entry.into_inner())
120+
.map(|(key, value)| K::try_from(key).and_then(|k| V::try_from(value).map(|v| (k, v))))
121+
.collect();
122+
123+
Some(map)
124+
}
125+
105126
/// Return `true` if the message is nil
106127
pub const fn is_nil(&self) -> bool {
107128
matches!(self, Self::Nil)
@@ -882,3 +903,16 @@ impl<'a> SizeableMessage for MessageRef<'a> {
882903
}
883904
}
884905
}
906+
907+
impl<'a, K, V> FromIterator<(K, V)> for MessageRef<'a>
908+
where
909+
K: Into<MessageRef<'a>>,
910+
V: Into<MessageRef<'a>>,
911+
{
912+
fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> Self {
913+
iter.into_iter()
914+
.map(|(key, value)| MapEntryRef::new(key.into(), value.into()))
915+
.collect::<Vec<_>>()
916+
.into()
917+
}
918+
}

msgpacker/tests/pack_unpack.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use msgpacker::prelude::*;
22

3+
use std::collections::HashMap;
34
use std::io::{self, Cursor, Seek};
45
use std::time::Duration;
56

@@ -139,3 +140,22 @@ fn pack_unpack() -> io::Result<()> {
139140

140141
Ok(())
141142
}
143+
144+
#[test]
145+
fn pack_unpack_map_works() {
146+
let data = vec![
147+
(10u32, String::from("test 1")),
148+
(38u32, String::from("")),
149+
(187u32, String::from("another test")),
150+
];
151+
152+
let map = data.clone().into_iter().collect::<HashMap<_, _>>();
153+
let msg = MessageRef::from_iter(map.iter().map(|(k, v)| (*k, v)));
154+
155+
let map_p = msg
156+
.try_collect_map()
157+
.expect("message is not a map")
158+
.expect("failed to parse items");
159+
160+
assert_eq!(map, map_p);
161+
}

0 commit comments

Comments
 (0)