mod cstr_ffi; mod last_error; mod object_pool; use object_pool::ObjectPool; use std::sync::{LazyLock, RwLock}; use thiserror::Error as TeError; use wfassoc::highlevel::{Program, Schema}; pub use cstr_ffi::CStyleString; pub use object_pool::Token; // region: Error /// Error occurs in this crate. #[derive(Debug, TeError)] enum Error { /// Error when operating Schema. #[error("{0}")] Schema(#[from] wfassoc::highlevel::SchemaError), /// Error when parsing Schema into Program. #[error("{0}")] ParseProgram(#[from] wfassoc::highlevel::ParseProgramError), /// Error when operating Program. #[error("{0}")] Program(#[from] wfassoc::highlevel::ProgramError), /// Error when manipulating with C-style string. #[error("{0}")] CStrFfi(#[from] cstr_ffi::Error), /// Error when manipulating with object pool. #[error("{0}")] ObjectPool(#[from] object_pool::Error), /// Error when manipulating with poison RwLock #[error("RwLock is poisoning")] PoisonRwLock, } /// Result type used in this crate. type Result = std::result::Result; // endregion // region: Macros macro_rules! in_param_ty { ($t:ty) => { $t }; } macro_rules! out_param_ty { ($t:ty) => { *mut $t }; } macro_rules! set_out_param { ($lhs:expr, $rhs:expr) => { unsafe { *$lhs = $rhs }; }; } macro_rules! pull_reader { ($pool:expr) => { $pool.read().map_err(|_| Error::PoisonRwLock) }; } macro_rules! pull_writer { ($pool:expr) => { $pool.write().map_err(|_| Error::PoisonRwLock) }; } // endregion // region: Exposed Functions // region: Facilities #[unsafe(no_mangle)] pub extern "C" fn WFStartup() -> bool { // TODO: Initialize all pool by fetching writer from them true } #[unsafe(no_mangle)] pub extern "C" fn WFShutdown() -> bool { // TODO: Free all pool stored objects true } #[unsafe(no_mangle)] pub extern "C" fn WFGetLastError() -> CStyleString { last_error::get_last_error() } #[unsafe(no_mangle)] pub extern "C" fn WFHasPrivilege() -> bool { wfassoc::win32::utilities::has_privilege() } // endregion // region: Schema static SCHEMA_POOL: LazyLock>> = LazyLock::new(|| RwLock::new(ObjectPool::new())); #[unsafe(no_mangle)] pub extern "C" fn WFSchemaCreate(out_schema: out_param_ty!(Token)) -> bool { fn inner() -> Result { let mut pool = pull_writer!(SCHEMA_POOL)?; Ok(pool.allocate(Schema::new())?) } match inner() { Ok(rv) => { set_out_param!(out_schema, rv); last_error::clear_last_error(); true } Err(e) => { last_error::set_last_error(e.to_string().as_str()); false } } } #[unsafe(no_mangle)] pub extern "C" fn WFSchemaSetIdentifier( in_schema: in_param_ty!(Token), in_value: in_param_ty!(CStyleString), ) -> bool { fn inner(in_schema: Token, in_value: CStyleString) -> Result<()> { let mut pool = pull_writer!(SCHEMA_POOL)?; let schema = pool.get_mut(in_schema)?; schema.set_identifier(cstr_ffi::parse_ffi_string(in_value)?); Ok(()) } match inner(in_schema, in_value) { Ok(_) => { last_error::clear_last_error(); true } Err(e) => { last_error::set_last_error(e.to_string().as_str()); false } } } #[unsafe(no_mangle)] pub extern "C" fn WFSchemaIntoProgram( in_schema: in_param_ty!(Token), out_program: out_param_ty!(Token), ) -> bool { fn inner(in_token: Token) -> Result { let mut pool = pull_writer!(SCHEMA_POOL)?; let schema = pool.pop(in_token)?; let mut pool = pull_writer!(PROGRAM_POOL)?; let program = schema.into_program()?; Ok(pool.allocate(program)?) } match inner(in_schema) { Ok(rv) => { set_out_param!(out_program, rv); last_error::clear_last_error(); true } Err(e) => { last_error::set_last_error(e.to_string().as_str()); false } } } #[unsafe(no_mangle)] pub extern "C" fn WFSchemaDestroy(in_schema: in_param_ty!(Token)) -> bool { fn inner(in_token: Token) -> Result<()> { let mut pool = pull_writer!(SCHEMA_POOL)?; Ok(pool.free(in_token)?) } match inner(in_schema) { Ok(_) => { last_error::clear_last_error(); true } Err(e) => { last_error::set_last_error(e.to_string().as_str()); false } } } // endregion // region: Program static PROGRAM_POOL: LazyLock>> = LazyLock::new(|| RwLock::new(ObjectPool::new())); // endregion // endregion