pub mod sieve;
pub mod tree;
pub mod walk;
use std::ffi::CString;
use std::path::Path;
use std::ptr::NonNull;
use std::sync::Arc;
use crate::Status;
use crate::error::{self, Error};
pub use sieve::{Facts, Freshness, Sieve, Winnow, WinnowFacts};
pub use tree::{Kind, Query, Record, Records, Search};
pub use walk::{Entry, Genus, Limits, Policy, Spec, Walk};
const PLANE: &str = "tree";
#[repr(C)]
struct EngineHandle {
_opaque: [u8; 0],
}
#[repr(C)]
struct CancelHandle {
_opaque: [u8; 0],
}
pub struct Corpus {
handle: NonNull<EngineHandle>,
}
impl Corpus {
pub fn open<P: AsRef<Path>>(roots: &[P]) -> Result<Self, Error> {
let owned = roots
.iter()
.map(|root| CString::new(root.as_ref().as_os_str().as_encoded_bytes()))
.collect::<Result<Vec<_>, _>>()
.map_err(|_| Error::Plane {
plane: PLANE,
status: Status::INVALID,
detail: Some("a root path contains an interior NUL byte".to_owned()),
})?;
let pointers: Vec<*const std::ffi::c_char> =
owned.iter().map(|root| root.as_ptr()).collect();
let mut out: *mut EngineHandle = std::ptr::null_mut();
let status =
unsafe { ffi::irgx_engine_open(pointers.as_ptr(), pointers.len(), &raw mut out) };
if status < 0 {
return Err(error::plane_fault(status, PLANE));
}
NonNull::new(out)
.map(|handle| Self { handle })
.ok_or_else(|| Error::Inconsistent {
message: "the engine reported success and produced no handle".to_owned(),
})
}
pub fn here() -> Result<Self, Error> {
Self::open::<&Path>(&[])
}
}
impl Drop for Corpus {
fn drop(&mut self) {
unsafe { ffi::irgx_engine_close(self.handle.as_ptr()) };
}
}
#[derive(Clone)]
pub struct Cancel {
token: Arc<Token>,
}
struct Token {
handle: NonNull<CancelHandle>,
}
unsafe impl Send for Token {}
unsafe impl Sync for Token {}
impl Drop for Token {
fn drop(&mut self) {
unsafe { ffi::irgx_cancel_free(self.handle.as_ptr()) };
}
}
impl Cancel {
pub fn new() -> Result<Self, Error> {
let mut out: *mut CancelHandle = std::ptr::null_mut();
let status = unsafe { ffi::irgx_cancel_new(&raw mut out) };
if status < 0 {
return Err(error::plane_fault(status, PLANE));
}
NonNull::new(out)
.map(|handle| Self {
token: Arc::new(Token { handle }),
})
.ok_or_else(|| Error::Inconsistent {
message: "the cancellation plane reported success and produced no token".to_owned(),
})
}
pub fn request(&self) {
unsafe { ffi::irgx_cancel_request(self.token.handle.as_ptr()) };
}
fn as_ptr(&self) -> *const CancelHandle {
self.token.handle.as_ptr()
}
}
impl std::fmt::Debug for Cancel {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Cancel")
.field("holders", &Arc::strong_count(&self.token))
.finish()
}
}
mod ffi {
use std::ffi::c_char;
use super::{CancelHandle, EngineHandle};
unsafe extern "C" {
pub fn irgx_engine_open(
roots: *const *const c_char,
nroots: usize,
out: *mut *mut EngineHandle,
) -> i32;
pub fn irgx_engine_close(engine: *mut EngineHandle);
pub fn irgx_cancel_new(out: *mut *mut CancelHandle) -> i32;
pub fn irgx_cancel_request(token: *mut CancelHandle);
pub fn irgx_cancel_free(token: *mut CancelHandle);
}
}