use std::{collections::HashMap, iter::FusedIterator};
#[derive(Debug, Default, Clone)]
pub struct UserMetadata {
metadata: HashMap<String, Vec<u8>>,
}
impl UserMetadata {
pub const MAX_KEY_LEN: usize = 2usize.pow(8);
pub const MAX_VALUE_LEN: usize = 2usize.pow(16);
}
impl UserMetadata {
pub fn new() -> Self {
Self {
metadata: HashMap::new(),
}
}
pub fn get<S: AsRef<str> + ?Sized>(&self, name: &S) -> Option<&[u8]> {
self.metadata.get(name.as_ref()).map(|v| v.as_ref())
}
pub fn set(&mut self, key: String, value: Vec<u8>) -> crate::Result<()> {
if key.len() > Self::MAX_KEY_LEN || value.len() > Self::MAX_VALUE_LEN {
return Err(crate::Error::MetadataLimitExceeded);
}
self.metadata.insert(key, value);
Ok(())
}
pub fn remove<S: AsRef<str> + ?Sized>(&mut self, name: &S) {
self.metadata.remove(name.as_ref());
}
pub fn clear(&mut self) {
self.metadata.clear();
}
pub fn iter(&self) -> UserMetadataIter<'_> {
UserMetadataIter {
inner: self.metadata.iter(),
}
}
}
#[derive(Debug)]
pub struct UserMetadataIter<'a> {
inner: std::collections::hash_map::Iter<'a, String, Vec<u8>>,
}
impl<'a> Iterator for UserMetadataIter<'a> {
type Item = (&'a str, &'a [u8]);
fn next(&mut self) -> Option<Self::Item> {
self.inner.next().map(|(k, v)| (k.as_ref(), v.as_ref()))
}
}
impl<'a> FusedIterator for UserMetadataIter<'a> {}
impl<'a> ExactSizeIterator for UserMetadataIter<'a> {
fn len(&self) -> usize {
self.inner.len()
}
}
#[derive(Debug)]
pub struct UserMetadataIntoIter {
inner: std::collections::hash_map::IntoIter<String, Vec<u8>>,
}
impl Iterator for UserMetadataIntoIter {
type Item = (String, Vec<u8>);
fn next(&mut self) -> Option<Self::Item> {
self.inner.next()
}
}
impl FusedIterator for UserMetadataIntoIter {}
impl ExactSizeIterator for UserMetadataIntoIter {
fn len(&self) -> usize {
self.inner.len()
}
}
impl IntoIterator for UserMetadata {
type Item = (String, Vec<u8>);
type IntoIter = UserMetadataIntoIter;
fn into_iter(self) -> Self::IntoIter {
UserMetadataIntoIter {
inner: self.metadata.into_iter(),
}
}
}
impl<'a> IntoIterator for &'a UserMetadata {
type Item = (&'a str, &'a [u8]);
type IntoIter = UserMetadataIter<'a>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}