#![allow(clippy::type_complexity)]
use super::*;
pub trait LogWriter: Log {
#[inline]
fn insert(&self, value: &[u8]) -> Result<ValuePointer<Self::Id>, Error>
where
Self::Id: CheapClone + core::fmt::Debug,
{
let vb = ValueBuilder::new(value.len(), |buf: &mut VacantBuffer<'_>| {
buf.put_slice_unchecked(value);
Ok(())
});
insert_in::<_, ()>(self, vb).map_err(|e| e.unwrap_right())
}
#[inline]
fn insert_tombstone(&self, value: &[u8]) -> Result<ValuePointer<Self::Id>, Error>
where
Self::Id: CheapClone + core::fmt::Debug,
{
self.insert(value).map(|vp| {
self.allocator().increase_discarded(value.len() as u32);
vp.with_tombstone()
})
}
}
pub trait LogWriterExt: LogWriter {
#[inline]
fn insert_generic<T>(&self, value: &T) -> Result<ValuePointer<Self::Id>, Either<T::Error, Error>>
where
T: Type,
Self::Id: CheapClone + core::fmt::Debug,
{
let encoded_len = value.encoded_len();
self.insert_with(ValueBuilder::new(
encoded_len,
|buf: &mut VacantBuffer<'_>| value.encode_to_buffer(buf).map(|_| ()),
))
}
#[inline]
fn insert_with<E>(
&self,
vb: ValueBuilder<impl FnOnce(&mut VacantBuffer<'_>) -> Result<(), E>>,
) -> Result<ValuePointer<Self::Id>, Either<E, Error>>
where
Self::Id: CheapClone + core::fmt::Debug,
{
insert_in(self, vb)
}
#[inline]
fn insert_generic_tombstone<T>(
&self,
value: &T,
) -> Result<ValuePointer<Self::Id>, Either<T::Error, Error>>
where
T: Type,
Self::Id: CheapClone + core::fmt::Debug,
{
let encoded_len = value.encoded_len();
self.insert_tombstone_with(ValueBuilder::new(
encoded_len,
|buf: &mut VacantBuffer<'_>| value.encode_to_buffer(buf).map(|_| ()),
))
}
#[inline]
fn insert_tombstone_with<E>(
&self,
vb: ValueBuilder<impl FnOnce(&mut VacantBuffer<'_>) -> Result<(), E>>,
) -> Result<ValuePointer<Self::Id>, Either<E, Error>>
where
Self::Id: CheapClone + core::fmt::Debug,
{
let encoded_len = vb.size;
insert_in(self, vb).map(|vp| {
self.allocator().increase_discarded(encoded_len as u32);
vp.with_tombstone()
})
}
}
impl<L> LogWriterExt for L where L: LogWriter {}
fn insert_in<L: LogWriter + ?Sized, E>(
l: &L,
vb: ValueBuilder<impl FnOnce(&mut VacantBuffer<'_>) -> Result<(), E>>,
) -> Result<ValuePointer<L::Id>, Either<E, Error>>
where
L::Id: CheapClone + core::fmt::Debug,
{
if vb.size == 0 {
return Ok(ValuePointer::new(l.id().cheap_clone(), 0, 0));
}
let opts = l.options();
let maximum = opts.max_value_size;
let (value_len, builder) = vb.into_components();
let len = value_len + CHECKSUM_LEN;
if len > maximum as usize {
return Err(Either::Right(Error::value_too_large(len, maximum as usize)));
}
let allocator = l.allocator();
let mut buf = allocator
.alloc_bytes(len as u32)
.map_err(|e| Either::Right(Error::from_insufficient_space(e)))?;
let begin_offset = buf.offset();
buf.set_len(value_len);
unsafe {
let ptr = NonNull::new_unchecked(buf.as_mut_ptr());
let mut vacant_buf = VacantBuffer::new(value_len, ptr);
builder(&mut vacant_buf).map_err(Either::Left)?;
let checksum = l.checksum(&buf);
buf.put_u64_le_unchecked(checksum);
}
#[cfg(all(feature = "memmap", not(target_family = "wasm")))]
if opts.sync && allocator.is_ondisk() {
allocator
.flush_header_and_range(begin_offset, len)
.map_err(|e| Either::Right(e.into()))?;
}
unsafe {
buf.detach();
}
Ok(ValuePointer::new(
l.id().cheap_clone(),
begin_offset as u32,
value_len as u32,
))
}
pub trait GenericLogWriter: Log {
type Type: Type;
fn insert(
&self,
value: &Self::Type,
) -> Result<ValuePointer<Self::Id>, Either<<Self::Type as Type>::Error, Error>>
where
Self::Id: CheapClone + core::fmt::Debug;
fn insert_tombstone(
&self,
value: &Self::Type,
) -> Result<ValuePointer<Self::Id>, Either<<Self::Type as Type>::Error, Error>>
where
Self::Id: CheapClone + core::fmt::Debug;
}
impl<L> GenericLogWriter for L
where
L: common::AsLog,
L::Type: Type,
L::Log: LogWriter,
<L::Log as Log>::Id: CheapClone + core::fmt::Debug,
{
type Type = L::Type;
#[inline]
fn insert(
&self,
value: &Self::Type,
) -> Result<ValuePointer<Self::Id>, Either<<Self::Type as Type>::Error, Error>>
where
Self::Id: CheapClone + core::fmt::Debug,
{
self.as_log().insert_generic(value)
}
#[inline]
fn insert_tombstone(
&self,
value: &Self::Type,
) -> Result<ValuePointer<Self::Id>, Either<<Self::Type as Type>::Error, Error>>
where
Self::Id: CheapClone + core::fmt::Debug,
{
self.as_log().insert_generic_tombstone(value)
}
}