Skip to content

Commit

Permalink
Expose methods to create RawMaps with custom hashers
Browse files Browse the repository at this point in the history
  • Loading branch information
Kerollmops committed Dec 10, 2024
1 parent f9b2a01 commit 47aa3eb
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 32 deletions.
77 changes: 55 additions & 22 deletions src/map.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::hash::BuildHasher;

use bumpalo::Bump;
use hashbrown::DefaultHashBuilder;
use serde::{ser::SerializeMap, Serialize};
Expand All @@ -21,16 +23,16 @@ pub mod iter;
///
/// All allocations happen in the associated [`Bump`].
#[derive(Debug)]
pub struct RawMap<'bump> {
pub struct RawMap<'bump, S = DefaultHashBuilder> {
data: BVec<'bump, (&'bump str, &'bump RawValue)>,
cache: hashbrown::HashMap<&'bump str, usize, DefaultHashBuilder, &'bump Bump>,
cache: hashbrown::HashMap<&'bump str, usize, S, &'bump Bump>,
}

impl Serialize for RawMap<'_> {
impl<S> Serialize for RawMap<'_, S> {
#[inline]
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
fn serialize<SE>(&self, serializer: SE) -> Result<SE::Ok, SE::Error>
where
S: serde::Serializer,
SE: serde::Serializer,
{
let mut map = serializer.serialize_map(Some(self.len()))?;
for (key, value) in self {
Expand All @@ -40,7 +42,7 @@ impl Serialize for RawMap<'_> {
}
}

impl<'bump> RawMap<'bump> {
impl<'bump> RawMap<'bump, DefaultHashBuilder> {
/// Constructs a map from a raw value and a bump allocator.
///
/// # Errors
Expand All @@ -62,6 +64,22 @@ impl<'bump> RawMap<'bump> {
cache: hashbrown::HashMap::new_in(bump),
}
}
}

impl<'bump, S: BuildHasher> RawMap<'bump, S> {
/// Constructs a map from a raw value and a bump allocator.
///
/// # Errors
///
/// - if the raw value cannot be parsed as a map (JSON object).
#[inline]
pub fn from_raw_value_and_hasher(
raw: &'bump RawValue,
hash_builder: S,
bump: &'bump Bump,
) -> Result<Self, serde_json::Error> {
Self::from_deserializer_and_hasher(raw, hash_builder, bump)
}

/// Inserts a new (key, value) pair in the map.
///
Expand Down Expand Up @@ -99,6 +117,28 @@ impl<'bump> RawMap<'bump> {
self.cache.get(key).copied()
}

/// Reserves capacity for at least additional more elements to be inserted in the map.
///
/// # Panics
///
/// - if the new capacity exceeds [`isize::MAX`].
#[inline]
pub fn reserve(&mut self, additional: usize) {
self.data.reserve(additional);
self.cache.reserve(additional);
}
}

impl<'bump, S> RawMap<'bump, S> {
/// Constructs an empty map backed by the specified bump allocator.
#[inline]
pub fn with_hasher_in(hash_builder: S, bump: &'bump Bump) -> Self {
Self {
data: BVec::new_in(bump),
cache: hashbrown::HashMap::with_hasher_in(hash_builder, bump),
}
}

/// The number of elements in the map.
#[inline]
pub fn len(&self) -> usize {
Expand All @@ -111,17 +151,6 @@ impl<'bump> RawMap<'bump> {
self.data.is_empty()
}

/// Reserves capacity for at least additional more elements to be inserted in the map.
///
/// # Panics
///
/// - if the new capacity exceeds [`isize::MAX`].
#[inline]
pub fn reserve(&mut self, additional: usize) {
self.data.reserve(additional);
self.cache.reserve(additional);
}

/// Returns the underlying vec as a slice.
#[inline]
pub fn as_slice(&self) -> &[(&'bump str, &'bump RawValue)] {
Expand All @@ -142,7 +171,7 @@ impl<'bump> RawMap<'bump> {

/// Makes this map [`Send`] by forbidding any future modifications.
#[inline]
pub fn freeze(&mut self) -> FrozenRawMap<'_, 'bump> {
pub fn freeze(&mut self) -> FrozenRawMap<'_, 'bump, S> {
FrozenRawMap::new(self)
}

Expand All @@ -154,21 +183,23 @@ impl<'bump> RawMap<'bump> {
}

/// A view into a [`RawMap`] that prevents insertions, but can be sent between threads safely.
pub struct FrozenRawMap<'a, 'bump> {
pub struct FrozenRawMap<'a, 'bump, S> {
data: &'a [(&'bump str, &'bump RawValue)],
cache: frozen::FrozenMap<'a, 'bump, &'bump str, usize, DefaultHashBuilder>,
cache: frozen::FrozenMap<'a, 'bump, &'bump str, usize, S>,
}

impl<'a, 'bump> FrozenRawMap<'a, 'bump> {
impl<'a, 'bump, S> FrozenRawMap<'a, 'bump, S> {
/// Makes the passed map [`Send`] by preventing any future modifications.
#[inline]
pub fn new(map: &'a mut RawMap<'bump>) -> Self {
pub fn new(map: &'a mut RawMap<'bump, S>) -> Self {
FrozenRawMap {
data: map.data.as_slice(),
cache: frozen::FrozenMap::new(&mut map.cache),
}
}
}

impl<'bump, S: BuildHasher> FrozenRawMap<'_, 'bump, S> {
/// Retrieves the value associated with a key, if present.
#[inline]
pub fn get(&self, key: &str) -> Option<&'bump RawValue> {
Expand All @@ -181,7 +212,9 @@ impl<'a, 'bump> FrozenRawMap<'a, 'bump> {
pub fn get_index(&self, key: &str) -> Option<usize> {
self.cache.get(key).copied()
}
}

impl<'a, 'bump, S> FrozenRawMap<'a, 'bump, S> {
/// The number of elements in the map.
#[inline]
pub fn len(&self) -> usize {
Expand Down
40 changes: 34 additions & 6 deletions src/map/de.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
use std::hash::BuildHasher;

use bumpalo::Bump;
use hashbrown::DefaultHashBuilder;
use serde::{de::Visitor, Deserializer};
use serde_json::value::RawValue;

use crate::{de::BumpStrSeed, RawMap};

pub struct BumpRawMapVisitor<'bump>(&'bump Bump);
pub struct BumpRawMapVisitor<'bump, S> {
bump: &'bump Bump,
hash_builder: S,
}

impl<'bump> Visitor<'bump> for BumpRawMapVisitor<'bump> {
type Value = RawMap<'bump>;
impl<'bump, S: BuildHasher> Visitor<'bump> for BumpRawMapVisitor<'bump, S> {
type Value = RawMap<'bump, S>;

fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(formatter, "a map")
Expand All @@ -18,12 +24,12 @@ impl<'bump> Visitor<'bump> for BumpRawMapVisitor<'bump> {
where
A: serde::de::MapAccess<'bump>,
{
let mut top = RawMap::new_in(self.0);
let mut top = RawMap::with_hasher_in(self.hash_builder, self.bump);

if let Some(size_hint) = map.size_hint() {
top.reserve(size_hint);
}
while let Some(key) = map.next_key_seed(BumpStrSeed(self.0))? {
while let Some(key) = map.next_key_seed(BumpStrSeed(self.bump))? {
let value: &'bump RawValue = map.next_value()?;
top.insert(key, value);
}
Expand All @@ -50,6 +56,28 @@ impl<'bump> RawMap<'bump> {
where
D: Deserializer<'bump>,
{
deserializer.deserialize_map(BumpRawMapVisitor(bump))
deserializer.deserialize_map(BumpRawMapVisitor {
bump,
hash_builder: DefaultHashBuilder::default(),
})
}
}

impl<'bump, S: BuildHasher> RawMap<'bump, S> {
/// Constructs a new map from a [`Deserializer`] and a `HashBuilder`.
///
/// # Errors
///
/// - the data does not deserializes as a map.
#[inline]
pub fn from_deserializer_and_hasher<D>(
deserializer: D,
hash_builder: S,
bump: &'bump Bump,
) -> Result<Self, D::Error>
where
D: Deserializer<'bump>,
{
deserializer.deserialize_map(BumpRawMapVisitor { bump, hash_builder })
}
}
9 changes: 5 additions & 4 deletions src/map/iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ impl<'bump> Iterator for Values<'bump, '_> {
///
/// Iterates in first-insertion order.
pub struct Iter<'bump, 'a>(std::slice::Iter<'a, (&'bump str, &'bump RawValue)>);

impl<'bump> Iterator for Iter<'bump, '_> {
type Item = (&'bump str, &'bump RawValue);

Expand All @@ -41,9 +42,8 @@ impl<'bump> Iterator for Iter<'bump, '_> {
}
}

impl<'bump> IntoIterator for RawMap<'bump> {
impl<'bump, S> IntoIterator for RawMap<'bump, S> {
type Item = (&'bump str, &'bump RawValue);

type IntoIter = IntoIter<'bump>;

#[inline]
Expand All @@ -58,6 +58,7 @@ impl<'bump> IntoIterator for RawMap<'bump> {
pub struct IntoIter<'bump>(
bumpalo::collections::vec::IntoIter<'bump, (&'bump str, &'bump RawValue)>,
);

impl<'bump> Iterator for IntoIter<'bump> {
type Item = (&'bump str, &'bump RawValue);

Expand All @@ -67,7 +68,7 @@ impl<'bump> Iterator for IntoIter<'bump> {
}
}

impl<'bump, 'a> IntoIterator for &'a RawMap<'bump> {
impl<'bump, 'a, S> IntoIterator for &'a RawMap<'bump, S> {
type Item = (&'bump str, &'bump RawValue);

type IntoIter = Iter<'bump, 'a>;
Expand All @@ -78,7 +79,7 @@ impl<'bump, 'a> IntoIterator for &'a RawMap<'bump> {
}
}

impl<'bump> RawMap<'bump> {
impl<'bump, S> RawMap<'bump, S> {
/// Iterates over the (key, value) pairs of the map in first-insertion order.
#[inline]
pub fn iter(&self) -> Iter<'bump, '_> {
Expand Down

0 comments on commit 47aa3eb

Please sign in to comment.