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 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
//! Serializer codec for serializing a list of strings as a set
//!
//! # Usage
//!
//! To use, annotate the field with `#[serde(with = "serde_dynamo::string_set")]`.
//!
//! DynamoDB will return an error if given an empty set. Thus, it may
//! be beneficial to additionally annotate the field with `#[serde(default)]`
//! and `#[serde(skip_serializing_if = "<empty check>")]`. This will make sure
//! that the field is omitted when empty.
//!
//! This serializer does not check for duplicate values or an empty set.
//! If the set contains duplicate values or is empty, DynamoDB will return a
//! validation error when the attribute value is used.
//!
//! # Errors
//!
//! The serializer in this module will return an error if:
//!
//! * the value does not serialize as a sequence
//! * the sequence contains any value that is not a string
//!
//! # Examples
//!
//! ```
//! use serde_derive::{Serialize, Deserialize};
//! use serde_dynamo::{Item, AttributeValue};
//!
//! #[derive(Serialize, Deserialize)]
//! struct MyStruct {
//! #[serde(with = "serde_dynamo::string_set")]
//! #[serde(default, skip_serializing_if = "Vec::is_empty")]
//! names: Vec<String>,
//! }
//!
//! let my_struct = MyStruct {
//! names: vec!["John".to_string(), "Jane".to_string()],
//! };
//!
//! let serialized: Item = serde_dynamo::to_item(&my_struct).unwrap();
//! assert_eq!(
//! serialized["names"],
//! AttributeValue::Ss(vec!["John".to_string(), "Jane".to_string()])
//! );
//! ```
pub(super) static NEWTYPE_SYMBOL: &str = "\u{037E}STRINGSET\u{037E}";
#[inline]
pub(crate) fn should_serialize_as_string_set(name: &str) -> bool {
std::ptr::eq(name, NEWTYPE_SYMBOL)
}
/// Serializes the given value as a string set
///
/// See the [module documentation][crate::string_set] for
/// additional usage information.
///
/// # Errors
///
/// The serializer in this module will return an error if:
///
/// * the value does not serialize as a sequence
/// * the sequence contains any value that is not a string
pub fn serialize<T, S>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
where
T: serde::Serialize,
S: serde::Serializer,
{
serializer.serialize_newtype_struct(NEWTYPE_SYMBOL, &value)
}
/// Deserializes the given value as a set
pub fn deserialize<'de, T, D>(deserializer: D) -> Result<T, D::Error>
where
T: serde::Deserialize<'de>,
D: serde::Deserializer<'de>,
{
T::deserialize(deserializer)
}
/// Serializes the wrapped value as a string set
///
/// This is useful for [`to_attribute_value`][crate::to_attribute_value]
/// when you want to serialize a sequence as a set of strings.
///
/// # Examples
///
/// ```
/// use serde_dynamo::{string_set::StringSet, AttributeValue};
///
/// let set = vec![
/// "orange",
/// "apple",
/// ];
///
/// let val: AttributeValue = serde_dynamo::to_attribute_value(StringSet(set)).unwrap();
/// assert_eq!(val, AttributeValue::Ss(vec![
/// "orange".to_string(),
/// "apple".to_string(),
/// ]));
/// ```
pub struct StringSet<T>(pub T);
impl<T> serde::Serialize for StringSet<T>
where
T: serde::Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_newtype_struct(NEWTYPE_SYMBOL, &self.0)
}
}
#[inline(never)]
pub(crate) fn convert_to_set(value: crate::AttributeValue) -> crate::Result<crate::AttributeValue> {
let vals = match value {
crate::AttributeValue::L(vals) => vals,
_ => return Err(crate::error::ErrorImpl::NotSetlike.into()),
};
let set = vals
.into_iter()
.map(|v| {
if let crate::AttributeValue::S(s) = v {
Ok(s)
} else {
Err(crate::error::ErrorImpl::StringSetExpectedType.into())
}
})
.collect::<Result<_, _>>()?;
Ok(crate::AttributeValue::Ss(set))
}
#[cfg(test)]
mod tests {
use serde_derive::{Deserialize, Serialize};
use crate::string_set::StringSet;
#[test]
fn newtype_strings_set_in_struct() {
let set = vec!["test".to_string(), "test2".to_string()];
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
struct Struct {
#[serde(with = "crate::string_set")]
set: Vec<String>,
}
let item: crate::Item = dbg!(crate::to_item(Struct { set }).unwrap());
assert_eq!(
item["set"],
crate::AttributeValue::Ss(vec!["test".to_string(), "test2".to_string(),])
);
}
#[test]
fn newtype_set_for_strings() {
let set = vec!["test", "test2"];
let val: crate::AttributeValue = dbg!(crate::to_attribute_value(StringSet(set)).unwrap());
assert_eq!(
val,
crate::AttributeValue::Ss(vec!["test".to_string(), "test2".to_string(),])
);
}
}