Skip to content

Commit 1c74738

Browse files
authored
Support SkipMap::insert_with
- Make `SkipMap::insert` and `SkipSet::insert` return the current value if the key and trailer already exist. - Add the `SkipMap::insert_with` method to support inserting an occupied key first, then write the value in the closure semantic.
1 parent 59c3d95 commit 1c74738

File tree

12 files changed

+438
-204
lines changed

12 files changed

+438
-204
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -54,21 +54,6 @@ jobs:
5454
- name: Apply clippy lints
5555
run: cargo clippy --all-features
5656

57-
# This represents the minimum Rust version supported by
58-
# Bytes. Updating this should be done in a dedicated PR.
59-
#
60-
# Tests are not run as tests may require newer versions of
61-
# rust.
62-
minrust:
63-
name: minrust
64-
runs-on: ubuntu-latest
65-
steps:
66-
- uses: actions/checkout@v3
67-
- name: Install Rust
68-
run: rustup update 1.72.0 && rustup default 1.72.0
69-
- name: Check
70-
run: . ci/test-stable.sh check
71-
7257
# Stable
7358
stable:
7459
name: stable
@@ -221,8 +206,7 @@ jobs:
221206
- stable
222207
- no_std
223208
- sanitizer
224-
- valgrind
225-
- minrust
209+
- valgrind
226210
steps:
227211
- uses: actions/checkout@v3
228212
- name: Install latest nightly

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# CHANGELOG
22

3+
## 0.8.0
4+
5+
- Make `SkipMap::insert` and `SkipSet::insert` return the current value if the key and trailer already exist.
6+
- Add the `SkipMap::insert_with` method to support inserting an occupied key first, then write the value in the closure semantic.
7+
38
## 0.7.0
49

510
- Implement `Iterator` for `MapIterator` and `SetIterator`.

Cargo.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "skl"
3-
version = "0.7.1"
3+
version = "0.8.0"
44
edition = "2021"
55
rust-version = "1.56.0"
66
repository = "https://github.com/al8n/skl-rs"
@@ -34,7 +34,7 @@ required-features = ["memmap"]
3434
default = ["std"]
3535
alloc = []
3636
memmap = ["memmap2", "fs4", "std"]
37-
std = ["rand/default"]
37+
std = ["rand/default", "either/default"]
3838

3939
[target.'cfg(loom)'.dependencies]
4040
loom = "0.7"
@@ -44,6 +44,7 @@ getrandom = { version = "0.2", features = ["js"] }
4444

4545
[dependencies]
4646
crossbeam-utils = { version = "0.8", default-features = false }
47+
either = { version = "1", default-features = false }
4748
rand = { version = "0.8", default-features = false, features = ["getrandom"] }
4849

4950
fs4 = { version = "0.8", optional = true }

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,14 @@
2828

2929
```toml
3030
[dependencies]
31-
skl = "0.7"
31+
skl = "0.8"
3232
```
3333

3434
- Enable memory map backend
3535

3636
```toml
3737
[dependencies]
38-
skl = { version = "0.7", features = ["memmap"] }
38+
skl = { version = "0.8", features = ["memmap"] }
3939
```
4040

4141
## Features

src/lib.rs

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,108 @@ impl Comparator for Descend {
130130
}
131131
}
132132

133+
/// Returns when the bytes are too large to be written to the occupied value.
134+
#[derive(Debug, Default, Clone, Copy)]
135+
pub struct TooLarge {
136+
remaining: usize,
137+
write: usize,
138+
}
139+
140+
impl core::fmt::Display for TooLarge {
141+
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
142+
write!(
143+
f,
144+
"OccupiedValue does not have enough space (remaining {}, want {})",
145+
self.remaining, self.write
146+
)
147+
}
148+
}
149+
150+
#[cfg(feature = "std")]
151+
impl std::error::Error for TooLarge {}
152+
153+
/// An occupied value in the skiplist.
154+
#[must_use = "occupied value must be fully filled with bytes."]
155+
#[derive(Debug)]
156+
pub struct OccupiedValue<'a> {
157+
value: &'a mut [u8],
158+
len: usize,
159+
cap: usize,
160+
}
161+
162+
impl<'a> OccupiedValue<'a> {
163+
/// Write bytes to the occupied value.
164+
pub fn write(&mut self, bytes: &[u8]) -> Result<(), TooLarge> {
165+
let len = bytes.len();
166+
let remaining = self.cap - self.len;
167+
if len > remaining {
168+
return Err(TooLarge {
169+
remaining,
170+
write: len,
171+
});
172+
}
173+
174+
self.value[self.len..self.len + len].copy_from_slice(bytes);
175+
self.len += len;
176+
Ok(())
177+
}
178+
179+
/// Returns the capacity of the occupied value.
180+
#[inline]
181+
pub const fn capacity(&self) -> usize {
182+
self.cap
183+
}
184+
185+
/// Returns the length of the occupied value.
186+
#[inline]
187+
pub const fn len(&self) -> usize {
188+
self.len
189+
}
190+
191+
/// Returns `true` if the occupied value is empty.
192+
#[inline]
193+
pub const fn is_empty(&self) -> bool {
194+
self.len == 0
195+
}
196+
197+
/// Returns the remaining space of the occupied value.
198+
#[inline]
199+
pub const fn remaining(&self) -> usize {
200+
self.cap - self.len
201+
}
202+
203+
#[inline]
204+
fn new(cap: usize, value: &'a mut [u8]) -> Self {
205+
Self { value, len: 0, cap }
206+
}
207+
}
208+
209+
impl<'a> core::ops::Deref for OccupiedValue<'a> {
210+
type Target = [u8];
211+
212+
fn deref(&self) -> &Self::Target {
213+
&self.value[..self.len]
214+
}
215+
}
216+
217+
impl<'a> core::ops::DerefMut for OccupiedValue<'a> {
218+
fn deref_mut(&mut self) -> &mut Self::Target {
219+
&mut self.value[..self.len]
220+
}
221+
}
222+
223+
impl<'a> Drop for OccupiedValue<'a> {
224+
fn drop(&mut self) {
225+
assert_eq!(
226+
self.len,
227+
self.cap,
228+
"OccupiedValue was not fully filled with bytes, capacity is {}, remaining is {}",
229+
self.cap,
230+
self.cap - self.len
231+
);
232+
}
233+
}
234+
133235
/// A trait for extra information that can be stored with entry in the skiplist.
134236
pub trait Trailer: Copy {
135237
/// Returns the version of the trailer.

0 commit comments

Comments
 (0)