1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
use core::{
fmt::{self, Write},
hash,
};
use aws_sdk_dynamodb::types::AttributeValue;
use itermap::IterMap;
use crate::path::Name;
use super::Value;
type MapType<K, V> = std::collections::HashMap<K, V>;
// TODO: Allow this to be configured via feature to switch between HashMap and BTreeMap
// type MapType<K, V> = std::collections::BTreeMap<K, V>;
/// <https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.NamingRulesDataTypes.html#HowItWorks.DataTypes.Document.Map>
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct Map {
map: MapType<Name, Value>,
}
impl Map {
pub fn new<T>(map: T) -> Self
where
T: Into<Map>,
{
map.into()
}
// Intentionally not using `impl From<ScalarValue> for AttributeValue` because
// I don't want to make this a public API people rely on. The purpose of this
// crate is not to make creating `AttributeValues` easier. They should try
// `serde_dynamo`.
pub(super) fn into_attribute_value(self) -> AttributeValue {
AttributeValue::M(
self.map
.into_iter()
.map_keys(|name| name.name)
.map_values(Value::into_attribute_value)
.collect(),
)
}
}
impl hash::Hash for Map {
fn hash<H>(&self, state: &mut H)
where
H: hash::Hasher,
{
self.map.iter().for_each(|(k, v)| {
k.hash(state);
v.hash(state);
})
}
}
impl fmt::Display for Map {
// TODO: Test this
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_char('{')?;
let mut first = true;
self.map.iter().try_for_each(|(k, v)| {
if first {
first = false;
} else {
f.write_str(", ")?;
}
write!(f, "{k}: {v}")
})?;
f.write_char('}')
}
}
impl<K, V> FromIterator<(K, V)> for Map
where
K: Into<Name>,
V: Into<Value>,
{
fn from_iter<I>(iter: I) -> Self
where
I: IntoIterator<Item = (K, V)>,
{
Self {
map: iter
.into_iter()
.map_keys(Into::into)
.map_values(Into::into)
.collect(),
}
}
}
impl<I, K, V> From<I> for Map
where
I: IntoIterator<Item = (K, V)>,
K: Into<Name>,
V: Into<Value>,
{
fn from(iter: I) -> Self {
Self::from_iter(iter)
}
}