Struct CompressedStream

Source
pub struct CompressedStream { /* private fields */ }
Available on crate feature stream only.
Expand description

Analogous to SerializedDb, but for serializing streams!

Implementations§

Source§

impl CompressedStream

Source

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().

Source

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(())
 }
Source

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(())
 }
Source

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(())
 }
Source

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(())
 }

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.