pub fn set_db_allocator(
    tracker: LayoutTracker
) -> Result<Option<LayoutTracker>, HyperscanRuntimeError>
Available on crate feature alloc only.
Expand description
 #[cfg(feature = "compiler")]
 fn main() -> Result<(), hyperscan::error::HyperscanError> {
   use hyperscan::{expression::*, flags::*, database::*, matchers::*, alloc::*};
   use std::{alloc::System, mem::ManuallyDrop};

   // Set the process-global allocator to use for Database instances:
   let tracker = LayoutTracker::new(System.into());
   // There was no custom allocator registered yet.
   assert!(set_db_allocator(tracker).unwrap().is_none());

   let expr: Expression = "asdf".parse()?;
   // Use ManuallyDrop to avoid calling the hyperscan db free method,
   // since we will be invalidating the pointer by changing the allocator,
   // and the .try_drop() method and Drop impl both call into
   // whatever allocator is currently active to free the pointer, which will error.
   let mut db = ManuallyDrop::new(expr.compile(Flags::SOM_LEFTMOST, Mode::BLOCK)?);

   // Change the allocator to a fresh LayoutTracker:
   let mut tracker = set_db_allocator(LayoutTracker::new(System.into())).unwrap().unwrap();
   // Get the extant allocations from the old LayoutTracker:
   let allocs = tracker.current_allocations();
   // Verify that only the single known db was allocated:
   assert_eq!(1, allocs.len());
   let (p, layout) = allocs[0];
   let db_ptr: *mut NativeDb = db.as_mut_native();
   assert_eq!(p.as_ptr() as *mut NativeDb, db_ptr);

   // Despite having reset the allocator, our previous db is still valid
   // and can be used for matching:
   let mut scratch = db.allocate_scratch()?;
   let mut matches: Vec<&str> = Vec::new();
   scratch.scan_sync(&db, "asdf asdf".into(), |m| {
     matches.push(unsafe { m.source.as_str() });
     MatchResult::Continue
   })?;
   assert_eq!(&matches, &["asdf", "asdf"]);

   // We can deserialize something from somewhere else into the db handle:
   let expr: Literal = "hello".parse()?;
   let serialized_db = expr.compile(Flags::SOM_LEFTMOST, Mode::BLOCK)?.serialize()?;
   // Ensure the allocated database is large enough to contain the deserialized one:
   assert!(layout.size() >= serialized_db.deserialized_size()?);
   // NB: overwrite the old database!
   unsafe { serialized_db.deserialize_db_at(db.as_mut_native())?; }

   // Reuse the same database object now:
   scratch.setup_for_db(&db)?;
   matches.clear();
   scratch.scan_sync(&db, "hello hello".into(), |m| {
     matches.push(unsafe { m.source.as_str() });
     MatchResult::Continue
   })?;
   assert_eq!(&matches, &["hello", "hello"]);

   // Need to deallocate the db by hand in order to drop the original LayoutTracker
   // without panicking:
   tracker.deallocate(p);
   // NB: `db` is now INVALID and points to FREED MEMORY!!!
   Ok(())
 }