pub struct CompressedStream { /* private fields */ }
stream
only.Expand description
Analogous to SerializedDb
, but for
serializing streams!
Implementations§
Source§impl CompressedStream
impl CompressedStream
Sourcepub fn into_buf(self) -> Box<[u8]>
pub fn into_buf(self) -> Box<[u8]>
Consume this struct and return the contents of the internal buffer.
The resulting box can be converted into a Vec
with
slice::into_vec()
.
Sourcepub fn compress(
into: CompressReserveBehavior,
live: &LiveStream,
) -> Result<Self, CompressionError>
pub fn compress( into: CompressReserveBehavior, live: &LiveStream, ) -> Result<Self, CompressionError>
Write the stream’s current state into a buffer according to the into
strategy.
The stream can later be deserialized from this state into a working
in-memory stream again with methods such as Self::expand()
.
If this method fails to allocate space due to the decision of the into
strategy, it will return CompressionError::NoSpace
.
Self::into_buf()
can be applied similarly to
CompressReserveBehavior::current_buf()
in order to reuse the backing
storage for a subsequent CompressReserveBehavior
request:
#[cfg(feature = "compiler")]
fn main() -> Result<(), vectorscan::error::VectorscanError> {
use vectorscan::{expression::*, flags::*, matchers::*, stream::*, state::*};
use std::{mem, ops::Range};
let a_expr: Expression = "a+".parse()?;
let b_expr: Expression = "b+".parse()?;
let a_db = a_expr.compile(Flags::SOM_LEFTMOST, Mode::STREAM | Mode::SOM_HORIZON_SMALL)?;
let b_db = b_expr.compile(Flags::SOM_LEFTMOST, Mode::STREAM | Mode::SOM_HORIZON_SMALL)?;
let mut scratch = Scratch::blank();
scratch.setup_for_db(&a_db)?;
scratch.setup_for_db(&b_db)?;
let a_live = a_db.allocate_stream()?;
let b_live = b_db.allocate_stream()?;
// Allocate a new buffer.
let a_compressed = a_live.compress(CompressReserveBehavior::NewBuf)?;
// We no longer need the old stream:
mem::drop(a_live);
// Deserialize the buffer into a new stream allocation:
let a_live = a_compressed.expand(&a_db)?;
// Extract the buffer: let's reuse it for another stream.
let buf: Vec<u8> = a_compressed.into_buf().into_vec();
let b_compressed = b_live.compress(CompressReserveBehavior::ExpandBuf(buf))?;
// We no longer need the old stream:
mem::drop(b_live);
// Deserialize the buffer into a new stream allocation:
let b_live = b_compressed.expand(&b_db)?;
let mut matches: Vec<StreamMatch> = Vec::new();
let mut match_fn = |m| {
matches.push(m);
MatchResult::Continue
};
// Both streams work:
{
let matcher = StreamMatcher::new(&mut match_fn);
let mut sink = ScratchStreamSink::new(a_live, matcher, scratch);
sink.scan("aardvarka".into())?;
sink.flush_eod()?;
// Overwrite the live stream object,
// but retain the scratch and match callback:
*sink.live.make_mut()? = b_live;
// The stream allocation from `a_live` has now been dropped!
sink.scan("imbibbe".into())?;
sink.flush_eod()?;
}
let matches: Vec<Range<usize>> = matches
.into_iter()
.map(|m| m.range.into())
.collect();
// The matches beginning with 2..3 are from `b_live`!
assert_eq!(&matches, &[0..1, 0..2, 5..6, 8..9, 2..3, 4..5, 4..6]);
Ok(())
}
Sourcepub fn expand(
&self,
db: &Database,
) -> Result<LiveStream, VectorscanRuntimeError>
pub fn expand( &self, db: &Database, ) -> Result<LiveStream, VectorscanRuntimeError>
Deserialize the current buffer into a newly allocated stream object.
#[cfg(feature = "compiler")]
fn main() -> Result<(), vectorscan::error::VectorscanError> {
use vectorscan::{expression::*, flags::*, stream::*, matchers::*};
use std::ops::Range;
let expr: Expression = "a+".parse()?;
let db = expr.compile(Flags::SOM_LEFTMOST, Mode::STREAM | Mode::SOM_HORIZON_SMALL)?;
let scratch = db.allocate_scratch()?;
let live = db.allocate_stream()?;
// Allocate a new buffer.
let behavior = CompressReserveBehavior::NewBuf;
// Compress into the buffer.
let compressed = live.compress(behavior)?;
// Deserialize the stream from the buffer into a new stream allocation:
let live2 = compressed.expand(&db)?;
let mut matches: Vec<StreamMatch> = Vec::new();
let mut match_fn = |m| {
matches.push(m);
MatchResult::Continue
};
// Both streams work:
{
let matcher = StreamMatcher::new(&mut match_fn);
let mut sink = ScratchStreamSink::new(live, matcher, scratch);
sink.scan("aardvarka".into())?;
sink.flush_eod()?;
// This is safe because `live` and `live2` are for the same db!
unsafe { sink.live.make_mut()?.try_clone_from(&live2)?; }
sink.scan("aardvarka".into())?;
sink.flush_eod()?;
}
let matches: Vec<Range<usize>> = matches
.into_iter()
.map(|m| m.range.into())
.collect();
// The second round of matches starting with 0..1 is from `live2`!
assert_eq!(&matches, &[0..1, 0..2, 5..6, 8..9, 0..1, 0..2, 5..6, 8..9]);
Ok(())
}
Sourcepub unsafe fn expand_into(
&self,
to: &mut LiveStream,
) -> Result<(), VectorscanRuntimeError>
pub unsafe fn expand_into( &self, to: &mut LiveStream, ) -> Result<(), VectorscanRuntimeError>
Deserialize the current buffer into a previously allocated stream object.
§Safety
self
and to
must have been opened against the same db!
#[cfg(feature = "compiler")]
fn main() -> Result<(), vectorscan::error::VectorscanError> {
use vectorscan::{expression::*, flags::*, stream::*, matchers::*};
use std::ops::Range;
let expr: Expression = "a+".parse()?;
let db = expr.compile(Flags::SOM_LEFTMOST, Mode::STREAM | Mode::SOM_HORIZON_SMALL)?;
let scratch = db.allocate_scratch()?;
let mut live = db.allocate_stream()?;
// Allocate a new buffer.
let behavior = CompressReserveBehavior::NewBuf;
// Compress into the buffer.
let compressed = live.compress(behavior)?;
// Expand into an existing live stream:
// This is safe because they were opened against the same db!
unsafe { compressed.expand_into(&mut live)?; }
let mut matches: Vec<StreamMatch> = Vec::new();
let mut match_fn = |m| {
matches.push(m);
MatchResult::Continue
};
// The stream works normally after expanding into it:
{
let matcher = StreamMatcher::new(&mut match_fn);
let mut sink = ScratchStreamSink::new(live, matcher, scratch);
sink.scan("aardvarka".into())?;
sink.flush_eod()?;
}
let matches: Vec<Range<usize>> = matches
.into_iter()
.map(|m| m.range.into())
.collect();
assert_eq!(&matches, &[0..1, 0..2, 5..6, 8..9]);
Ok(())
}
Sourcepub unsafe fn expand_into_at(
&self,
db: &Database,
to: *mut NativeStream,
) -> Result<(), VectorscanRuntimeError>
pub unsafe fn expand_into_at( &self, db: &Database, to: *mut NativeStream, ) -> Result<(), VectorscanRuntimeError>
Deserialize the current buffer into an allocation from anywhere at all.
§Safety
to
must point to an allocation of at least Database::stream_size()
bytes in size given db
!
#[cfg(feature = "compiler")]
fn main() -> Result<(), vectorscan::error::VectorscanError> {
use vectorscan::{expression::*, flags::*, stream::*, matchers::*};
use std::{mem, ops::Range};
let expr: Expression = "a+".parse()?;
let db = expr.compile(Flags::SOM_LEFTMOST, Mode::STREAM | Mode::SOM_HORIZON_SMALL)?;
let scratch = db.allocate_scratch()?;
let live = db.allocate_stream()?;
// Allocate a new buffer.
let behavior = CompressReserveBehavior::NewBuf;
// Compress into the buffer.
let compressed = live.compress(behavior)?;
// Expand into a stream allocated from somewhere totally different:
let mut allocation = vec![0; db.stream_size()?];
let live2 = unsafe {
let allocation = allocation.as_mut_ptr() as *mut NativeStream;
compressed.expand_into_at(&db, allocation)?;
// ManuallyDrop avoids calling the stream dealloc method on our vector data:
mem::ManuallyDrop::new(LiveStream::from_native(allocation))
};
let mut matches: Vec<StreamMatch> = Vec::new();
let mut match_fn = |m| {
matches.push(m);
MatchResult::Continue
};
// Both streams work:
{
let matcher = StreamMatcher::new(&mut match_fn);
let mut sink = ScratchStreamSink::new(live, matcher, scratch);
sink.scan("aardvarka".into())?;
sink.flush_eod()?;
// This is safe because `live` and `live2` are for the same db!
unsafe { sink.live.make_mut()?.try_clone_from(&live2)?; }
sink.scan("aardvarka".into())?;
sink.flush_eod()?;
}
let matches: Vec<Range<usize>> = matches
.into_iter()
.map(|m| m.range.into())
.collect();
assert_eq!(&matches, &[0..1, 0..2, 5..6, 8..9, 0..1, 0..2, 5..6, 8..9]);
Ok(())
}