gvox_rs/
lib.rs

1//! ## Safe, high-level Rust API for the [GVOX voxel data library](https://github.com/GabeRundlett/gvox)
2//!
3//! This library supplies an idiomatic Rust abstraction over the GVOX C API. It provides type safety, memory safety, and thread safety
4//! without any significant deviation from the C library's design. For more information on the API's design, see the [GVOX Wiki](https://github.com/GabeRundlett/gvox/wiki).
5//!
6//! Below is a simple example which demonstrates how to create adapter contexts and utilize them to convert a `.gvox` file to colored text console output.
7//! For additional examples, see the tests in `src/tests.rs`.
8//!
9//! ```rust
10//! const BYTES: &[u8] = include_bytes!("palette.gvox");
11//! let mut o_buffer = Box::default();
12//! {
13//!     let gvox_ctx = gvox_rs::Context::new();
14//!     gvox_ctx.register_adapter::<gvox_rs::Parse, procedural_parse::Procedural>();
15//!     let o_config = gvox_rs::adapters::ByteBufferOutputAdapterConfig::from(&mut o_buffer);
16//!     let s_config = gvox_rs::adapters::ColoredTextSerializeAdapterConfig {
17//!         downscale_factor: 1,
18//!         downscale_mode: gvox_rs::adapters::ColoredTextSerializeAdapterDownscaleMode::Nearest,
19//!         non_color_max_value: 5,
20//!         vertical: false,
21//!     };
22//!     let mut i_ctx = gvox_ctx
23//!         .get_adapter::<gvox_rs::Input, gvox_rs::adapters::ByteBuffer>()
24//!         .expect("Failed to get byte buffer input adapter.")
25//!         .create_adapter_context(PALETTE_BYTES)
26//!         .expect("Failed to create adapter context.");
27//!     let mut o_ctx = gvox_ctx
28//!         .get_adapter::<gvox_rs::Output, gvox_rs::adapters::ByteBuffer>()
29//!         .expect("Failed to get byte buffer output adapter.")
30//!         .create_adapter_context(o_config)
31//!         .expect("Failed to create adapter context.");
32//!     let mut p_ctx = gvox_ctx
33//!         .get_adapter::<gvox_rs::Parse, gvox_rs::adapters::GvoxPalette>()
34//!         .expect("Failed to get gvox palette parse adapter.")
35//!         .create_adapter_context(())
36//!         .expect("Failed to create adapter context.");
37//!     let mut s_ctx = gvox_ctx
38//!         .get_adapter::<gvox_rs::Serialize, gvox_rs::adapters::ColoredText>()
39//!         .expect("Failed to get colored text serialize adapter.")
40//!         .create_adapter_context(s_config)
41//!         .expect("Failed to create adapter context.");
42//!     gvox_rs::blit_region(
43//!         Some(&mut i_ctx),
44//!         Some(&mut o_ctx),
45//!         &mut p_ctx,
46//!         &mut s_ctx,
47//!         None, // Parse whole file!
48//!         gvox_rs::ChannelId::COLOR
49//!             | gvox_rs::ChannelId::NORMAL
50//!             | gvox_rs::ChannelId::MATERIAL_ID,
51//!     )
52//!     .expect("Error while translating.");
53//! }
54//! assert_eq!(
55//!     33342,
56//!     o_buffer.len(),
57//!     "Buffer output length did not match expected."
58//! );
59//! println!(
60//!     "{}",
61//!     std::str::from_utf8(&o_buffer).expect("Bad string slice.")
62//! );
63//! ```
64//!
65//! ## Building
66//! For now, you must have the following things installed to build the repository
67//!  * A C++ compiler
68//!  * CMake (3.21 or higher)
69//!  * Ninja build
70//!  * vcpkg (plus the VCPKG_ROOT environment variable)
71//!  * The latest WASI_SDK (if you are building for WASM)
72
73/// The set of default adapters that come built-in.
74pub mod adapters;
75
76// Comment out to test the Wasm support
77#[cfg(test)]
78mod tests;
79
80// Uncomment to test the Wasm support
81// pub fn main() {
82//     tests::gvox_rs_test_version();
83// }
84
85use bitflags::*;
86use fxhash::*;
87use std::any::*;
88use std::collections::hash_map::*;
89use std::error::*;
90use std::ffi::*;
91use std::marker::*;
92use std::mem::*;
93use std::ops::*;
94use std::slice::*;
95use std::sync::*;
96
97#[derive(Copy, Clone, Debug, PartialEq, Eq)]
98pub struct Version {
99    pub major: u32,
100    pub minor: u32,
101    pub patch: u32,
102}
103
104pub fn get_version() -> Version {
105    let mut result = gvox_sys::GvoxVersion {
106        major: 0,
107        minor: 0,
108        patch: 0,
109    };
110    unsafe {
111        gvox_sys::gvox_get_version(&mut result);
112    }
113    Version {
114        major: result.major,
115        minor: result.minor,
116        patch: result.patch,
117    }
118}
119
120/// Copies a range of voxel data from the specified input
121/// to the specified output, parsing and then serializing
122/// the data using the provided format adapters.
123pub fn blit_region(
124    input_ctx: Option<&mut AdapterContext<'_, Input>>,
125    output_ctx: Option<&mut AdapterContext<'_, Output>>,
126    parse_ctx: &mut AdapterContext<'_, Parse>,
127    serialize_ctx: &mut AdapterContext<'_, Serialize>,
128    range: Option<&RegionRange>,
129    channel_flags: ChannelFlags,
130) -> Result<(), GvoxError> {
131    unsafe {
132        parse_ctx.context().execute_inner(|ctx| {
133            gvox_sys::gvox_blit_region(
134                if input_ctx.is_some() {
135                    input_ctx.unwrap().as_mut_ptr()
136                } else {
137                    std::ptr::null_mut() as *mut gvox_sys::GvoxAdapterContext
138                },
139                if output_ctx.is_some() {
140                    output_ctx.unwrap().as_mut_ptr()
141                } else {
142                    std::ptr::null_mut() as *mut gvox_sys::GvoxAdapterContext
143                },
144                parse_ctx.as_mut_ptr(),
145                serialize_ctx.as_mut_ptr(),
146                if range.is_some() {
147                    range.unwrap() as *const RegionRange as *const gvox_sys::GvoxRegionRange
148                } else {
149                    std::ptr::null() as *const gvox_sys::GvoxRegionRange
150                },
151                channel_flags.into(),
152            );
153
154            ctx.get_error()
155        })
156    }
157}
158
159/// Does the same as blit_region, but explicitly sets the blit mode to prefer parse-driven
160pub fn blit_region_parse_driven(
161    input_ctx: Option<&mut AdapterContext<'_, Input>>,
162    output_ctx: Option<&mut AdapterContext<'_, Output>>,
163    parse_ctx: &mut AdapterContext<'_, Parse>,
164    serialize_ctx: &mut AdapterContext<'_, Serialize>,
165    range: Option<&RegionRange>,
166    channel_flags: ChannelFlags,
167) -> Result<(), GvoxError> {
168    unsafe {
169        parse_ctx.context().execute_inner(|ctx| {
170            gvox_sys::gvox_blit_region_parse_driven(
171                if input_ctx.is_some() {
172                    input_ctx.unwrap().as_mut_ptr()
173                } else {
174                    std::ptr::null_mut() as *mut gvox_sys::GvoxAdapterContext
175                },
176                if output_ctx.is_some() {
177                    output_ctx.unwrap().as_mut_ptr()
178                } else {
179                    std::ptr::null_mut() as *mut gvox_sys::GvoxAdapterContext
180                },
181                parse_ctx.as_mut_ptr(),
182                serialize_ctx.as_mut_ptr(),
183                if range.is_some() {
184                    range.unwrap() as *const RegionRange as *const gvox_sys::GvoxRegionRange
185                } else {
186                    std::ptr::null() as *const gvox_sys::GvoxRegionRange
187                },
188                channel_flags.into(),
189            );
190
191            ctx.get_error()
192        })
193    }
194}
195
196/// Does the same as blit_region, but explicitly sets the blit mode to prefer serialize-driven
197pub fn blit_region_serialize_driven(
198    input_ctx: Option<&mut AdapterContext<'_, Input>>,
199    output_ctx: Option<&mut AdapterContext<'_, Output>>,
200    parse_ctx: &mut AdapterContext<'_, Parse>,
201    serialize_ctx: &mut AdapterContext<'_, Serialize>,
202    range: Option<&RegionRange>,
203    channel_flags: ChannelFlags,
204) -> Result<(), GvoxError> {
205    unsafe {
206        parse_ctx.context().execute_inner(|ctx| {
207            gvox_sys::gvox_blit_region_serialize_driven(
208                if input_ctx.is_some() {
209                    input_ctx.unwrap().as_mut_ptr()
210                } else {
211                    std::ptr::null_mut() as *mut gvox_sys::GvoxAdapterContext
212                },
213                if output_ctx.is_some() {
214                    output_ctx.unwrap().as_mut_ptr()
215                } else {
216                    std::ptr::null_mut() as *mut gvox_sys::GvoxAdapterContext
217                },
218                parse_ctx.as_mut_ptr(),
219                serialize_ctx.as_mut_ptr(),
220                if range.is_some() {
221                    range.unwrap() as *const RegionRange as *const gvox_sys::GvoxRegionRange
222                } else {
223                    std::ptr::null() as *const gvox_sys::GvoxRegionRange
224                },
225                channel_flags.into(),
226            );
227
228            ctx.get_error()
229        })
230    }
231}
232
233/// Stores the capabilities, information, and state about a set of voxel blitting operations.
234/// Adapters can be created or obtained from contexts.
235#[derive(Clone, Debug, Default)]
236pub struct Context(Arc<Mutex<ContextInner>>);
237
238impl Context {
239    /// Creates a new context for voxel format operations.
240    pub fn new() -> Self {
241        Self::default()
242    }
243
244    /// Gets the adapter of the provided type and description, or returns an error if it could not be found.
245    pub fn get_adapter<K: AdapterKind, A: AdapterDescriptor<K> + NamedAdapter>(
246        &self,
247    ) -> Result<Adapter<K, A>, GvoxError> {
248        let ptr = self.execute_inner(|ctx| ctx.get_raw_adapter::<K, A>())?;
249
250        Ok(Adapter {
251            ctx: self.clone(),
252            ptr,
253            data: PhantomData::default(),
254        })
255    }
256
257    /// Registers an adapter for future use, or returns an error if it could not be added.
258    pub fn register_adapter<
259        K: AdapterKind,
260        A: AdapterDescriptor<K> + NamedAdapter + private::RegisterableAdapter<K>,
261    >(
262        &self,
263    ) -> Result<Adapter<K, A>, GvoxError> {
264        self.execute_inner(|ctx| ctx.register_adapter::<K, A>())?;
265        self.get_adapter::<K, A>()
266    }
267
268    /// Retrieves a raw handle to the context.
269    pub fn as_mut_ptr(&self) -> *mut gvox_sys::GvoxContext {
270        self.execute_inner(|ctx| ctx.ptr)
271    }
272
273    /// Executes the provided function synchronously on the context's inner data, and returns the result.
274    fn execute_inner<T>(&self, f: impl FnOnce(&mut ContextInner) -> T) -> T {
275        f(&mut self.0.lock().expect("Could not acquire context mutex."))
276    }
277}
278
279impl PartialEq for Context {
280    fn eq(&self, other: &Self) -> bool {
281        Arc::ptr_eq(&self.0, &other.0)
282    }
283}
284
285impl Eq for Context {}
286
287unsafe impl Send for Context {}
288unsafe impl Sync for Context {}
289
290/// Stores the inner, synchronized state of a context.
291#[derive(Clone, Debug)]
292struct ContextInner {
293    /// A pointer to the underlying native context.
294    ptr: *mut gvox_sys::GvoxContext,
295    /// All of the known adapter names, and their associated type handlers.
296    registered_adapter_types: FxHashMap<AdapterIdentifier, TypeId>,
297}
298
299impl ContextInner {
300    /// Gets a raw, non-null pointer to the adapter of the given type and name. Returns an
301    /// error if the adapter could not be found or was not of the correct type.
302    pub fn get_raw_adapter<K: AdapterKind, A: NamedAdapter>(
303        &self,
304    ) -> Result<*mut gvox_sys::GvoxAdapter, GvoxError> {
305        unsafe {
306            let adapter_type = self
307                .registered_adapter_types
308                .get(&AdapterIdentifier::new::<K, A>());
309            if adapter_type == Some(&TypeId::of::<A>()) {
310                let c_name =
311                    CString::new(A::name()).expect("Failed to convert Rust string to C string");
312                let kind = TypeId::of::<K>();
313
314                let adapter = if kind == TypeId::of::<Input>() {
315                    gvox_sys::gvox_get_input_adapter(self.ptr, c_name.as_ptr())
316                } else if kind == TypeId::of::<Output>() {
317                    gvox_sys::gvox_get_output_adapter(self.ptr, c_name.as_ptr())
318                } else if kind == TypeId::of::<Parse>() {
319                    gvox_sys::gvox_get_parse_adapter(self.ptr, c_name.as_ptr())
320                } else if kind == TypeId::of::<Serialize>() {
321                    gvox_sys::gvox_get_serialize_adapter(self.ptr, c_name.as_ptr())
322                } else {
323                    return Err(GvoxError::new(
324                        ErrorType::Unknown,
325                        "Unrecognized adapter type.".to_string(),
326                    ));
327                };
328
329                self.get_error()
330                    .and((!adapter.is_null()).then_some(adapter).ok_or_else(|| {
331                        GvoxError::new(ErrorType::Unknown, "Adapter not found.".to_string())
332                    }))
333            } else if adapter_type.is_some() {
334                Err(GvoxError::new(
335                    ErrorType::InvalidParameter,
336                    "The provided adapter was not of the correct type.".to_string(),
337                ))
338            } else {
339                Err(GvoxError::new(
340                    ErrorType::InvalidParameter,
341                    "The provided adapter was not found.".to_string(),
342                ))
343            }
344        }
345    }
346
347    /// Registers an adapter for voxel conversion operations, and returns a raw pointer to the adapter.
348    fn register_adapter<K: AdapterKind, A: private::RegisterableAdapter<K>>(
349        &mut self,
350    ) -> Result<*mut gvox_sys::GvoxAdapter, GvoxError> {
351        unsafe {
352            let adapter = A::register_adapter(self.ptr)?;
353            self.add_external_adapter::<K, A>()?;
354            Ok(adapter)
355        }
356    }
357
358    /// Obtains a raw pointer to a new adapter context, using the given adapter and configuration.
359    ///
360    /// # Safety
361    ///
362    /// Adapter must be a valid adapter associated with this context, and config must point to a datastructure
363    /// of the correct layout for the given adapter.
364    pub unsafe fn create_raw_adapter_context(
365        &mut self,
366        adapter: *mut gvox_sys::GvoxAdapter,
367        config: *const c_void,
368    ) -> Result<*mut gvox_sys::GvoxAdapterContext, GvoxError> {
369        let result = gvox_sys::gvox_create_adapter_context(self.ptr, adapter, config);
370        self.get_error()?;
371        Ok(result)
372    }
373
374    /// Adds an external adapter (one that was already registered with the context outside of this API)
375    /// to this context, so that it may be safely retrieved and used.
376    ///
377    /// # Safety
378    ///
379    /// For this call to be sound, the provided adapter must have already been registered
380    /// with the given name on the underlying context. The adapter must support operations
381    /// for the selected adapter kind, and the configuration structure that the adapter accepts
382    /// must match that of the underlying context.
383    pub unsafe fn add_external_adapter<K: AdapterKind, A: AdapterDescriptor<K> + NamedAdapter>(
384        &mut self,
385    ) -> Result<(), GvoxError> {
386        match self
387            .registered_adapter_types
388            .entry(AdapterIdentifier::new::<K, A>())
389        {
390            Entry::Vacant(v) => {
391                v.insert(TypeId::of::<A>());
392                Ok(())
393            }
394            Entry::Occupied(_) => Err(GvoxError::new(
395                ErrorType::InvalidParameter,
396                "Attempted to register duplicate adapter.".to_string(),
397            )),
398        }
399    }
400
401    /// Adds all builtin adapters to the context, so that they may be queried and used.
402    fn add_default_adapters(&mut self) -> Result<(), GvoxError> {
403        unsafe {
404            self.add_external_adapter::<Input, adapters::ByteBuffer>()?;
405            self.add_external_adapter::<Output, adapters::ByteBuffer>()?;
406            self.add_external_adapter::<Output, adapters::StdOut>()?;
407            self.add_external_adapter::<Parse, adapters::GvoxPalette>()?;
408            self.add_external_adapter::<Parse, adapters::GvoxRaw>()?;
409            self.add_external_adapter::<Parse, adapters::GvoxBrickmap>()?;
410            self.add_external_adapter::<Parse, adapters::GvoxGlobalPalette>()?;
411            self.add_external_adapter::<Parse, adapters::GvoxOctree>()?;
412            self.add_external_adapter::<Parse, adapters::GvoxRunLengthEncoding>()?;
413            self.add_external_adapter::<Parse, adapters::MagicaVoxel>()?;
414            self.add_external_adapter::<Parse, adapters::Voxlap>()?;
415            self.add_external_adapter::<Parse, adapters::Kvx>()?;
416            self.add_external_adapter::<Serialize, adapters::ColoredText>()?;
417            self.add_external_adapter::<Serialize, adapters::GvoxPalette>()?;
418            self.add_external_adapter::<Serialize, adapters::GvoxRaw>()?;
419            self.add_external_adapter::<Serialize, adapters::GvoxBrickmap>()?;
420            self.add_external_adapter::<Serialize, adapters::GvoxGlobalPalette>()?;
421            self.add_external_adapter::<Serialize, adapters::GvoxOctree>()?;
422            self.add_external_adapter::<Serialize, adapters::GvoxRunLengthEncoding>()?;
423
424            Ok(())
425        }
426    }
427
428    /// Flushes the context error stack, and returns the topmost error.
429    fn get_error(&self) -> Result<(), GvoxError> {
430        unsafe { Self::get_error_from_raw_ptr(self.ptr) }
431    }
432
433    /// Flushes the error stack of the provided context, and returns the topmost error.
434    pub unsafe fn get_error_from_raw_ptr(ptr: *mut gvox_sys::GvoxContext) -> Result<(), GvoxError> {
435        let mut result = Ok(());
436
437        let mut code = gvox_sys::gvox_get_result(ptr);
438        let mut buf = Vec::new();
439        while code != gvox_sys::GvoxResult_GVOX_RESULT_SUCCESS {
440            let mut msg_size = 0;
441            gvox_sys::gvox_get_result_message(ptr, std::ptr::null_mut(), &mut msg_size);
442            buf.resize(msg_size, 0);
443            gvox_sys::gvox_get_result_message(ptr, buf.as_mut_ptr() as *mut i8, &mut msg_size);
444
445            result = Err(GvoxError::new(ErrorType::from(code),
446                std::str::from_utf8(buf.as_slice())
447                    .unwrap_or_default()
448                    .to_string(),
449            ));
450
451            gvox_sys::gvox_pop_result(ptr);
452            code = gvox_sys::gvox_get_result(ptr);
453        }
454
455        result
456    }
457}
458
459impl Default for ContextInner {
460    fn default() -> Self {
461        unsafe {
462            let ptr = gvox_sys::gvox_create_context();
463            let registered_adapter_types = FxHashMap::default();
464            let mut res = Self {
465                ptr,
466                registered_adapter_types,
467            };
468            res.add_default_adapters()
469                .expect("Could not add default adapters to gvox context.");
470
471            res
472        }
473    }
474}
475
476impl Drop for ContextInner {
477    fn drop(&mut self) {
478        unsafe { gvox_sys::gvox_destroy_context(self.ptr) }
479    }
480}
481
482/// Uniquely identifies an adapter registration by name and kind.
483#[derive(Clone, Debug, PartialEq, Eq, Hash)]
484struct AdapterIdentifier {
485    /// The name of this adapter.
486    name: &'static str,
487    /// The ID of the adapter kind.
488    kind: TypeId,
489}
490
491impl AdapterIdentifier {
492    /// Creates a new identifier for the provided adapter name and kind.
493    pub fn new<K: AdapterKind, A: NamedAdapter>() -> Self {
494        Self {
495            name: A::name(),
496            kind: TypeId::of::<K>(),
497        }
498    }
499}
500
501/// Acts as an abstract interface over the ability to read, write, parse, and serialize voxel data.
502#[derive(Clone, Debug, PartialEq, Eq)]
503pub struct Adapter<K: AdapterKind, A: AdapterDescriptor<K>> {
504    /// The context that created this adapter.
505    ctx: Context,
506    /// A reference to the underlying adapter.
507    ptr: *mut gvox_sys::GvoxAdapter,
508    /// Marks that this type uses its generic paramters.
509    data: PhantomData<(K, A)>,
510}
511
512impl<K: AdapterKind, A: AdapterDescriptor<K>> Adapter<K, A> {
513    /// The context to which this adapter belongs.
514    pub fn context(&self) -> Context {
515        self.ctx.clone()
516    }
517
518    /// Creates a new adapter context instance, with the given configuration, that can be utilized to perform voxel blitting operations.
519    pub fn create_adapter_context<'a>(
520        &self,
521        config: A::Configuration<'a>,
522    ) -> Result<AdapterContext<'a, K>, GvoxError> {
523        unsafe {
524            let ctx = self.context();
525            let ptr = self.ctx.execute_inner(|ctx| {
526                ctx.create_raw_adapter_context(
527                    self.ptr,
528                    &config as *const A::Configuration<'a> as *const c_void,
529                )
530            })?;
531
532            if !ExternalHandler::is_external::<K, A>() {
533                AdapterContextHolder::from_raw(ptr)
534                    .get_context_data()
535                    .expect("No user data was associated with context.")
536                    .ctx = self.ctx.as_mut_ptr();
537            }
538
539            Ok(AdapterContext {
540                ctx,
541                ptr,
542                data: PhantomData::default(),
543            })
544        }
545    }
546
547    /// Retrieves a raw handle to the adapter.
548    pub fn as_mut_ptr(&mut self) -> *mut gvox_sys::GvoxAdapter {
549        self.ptr
550    }
551}
552
553/// One specific instance of a configured adapter that can be used to perform blitting operations.
554#[derive(Debug, PartialEq, Eq)]
555pub struct AdapterContext<'a, K: AdapterKind> {
556    /// The associated context.
557    ctx: Context,
558    /// A reference to the underlying adapter context.
559    ptr: *mut gvox_sys::GvoxAdapterContext,
560    /// Marks that this type makes use of its generic parameters.
561    data: PhantomData<(&'a (), K)>,
562}
563
564impl<'a, K: AdapterKind> AdapterContext<'a, K> {
565    /// The context to which this adapter context belongs.
566    pub fn context(&self) -> Context {
567        self.ctx.clone()
568    }
569
570    /// Retrieves a raw handle to the adapter context.
571    pub fn as_mut_ptr(&mut self) -> *mut gvox_sys::GvoxAdapterContext {
572        self.ptr
573    }
574}
575
576impl<'a, K: AdapterKind> Drop for AdapterContext<'a, K> {
577    fn drop(&mut self) {
578        unsafe {
579            gvox_sys::gvox_destroy_adapter_context(self.as_mut_ptr());
580        }
581    }
582}
583
584/// Describes the purpose of a particular adapter.
585pub trait AdapterKind: 'static + private::Sealed {}
586
587/// Marks types that read voxel input data.
588#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
589pub struct Input;
590
591impl AdapterKind for Input {}
592
593/// Marks types that write voxel output data.
594#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
595pub struct Output;
596
597impl AdapterKind for Output {}
598
599/// Marks types that decode voxel data from a provided input stream.
600#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
601pub struct Parse;
602
603impl AdapterKind for Parse {}
604
605/// Marks types that encode voxel data from a provided parser.
606#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
607pub struct Serialize;
608
609impl AdapterKind for Serialize {}
610
611/// Marks types that which have blit callbacks handled externally.
612#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
613pub struct ExternalHandler;
614
615impl ExternalHandler {
616    /// Determines whether the provided adapter descriptor is an externally managed (native) adapter.
617    pub fn is_external<K: AdapterKind, A: AdapterDescriptor<K>>() -> bool {
618        TypeId::of::<Self>() == TypeId::of::<A::Handler>()
619    }
620}
621
622/// Describes the layout of an adapter and its configuration type.
623pub trait AdapterDescriptor<K: AdapterKind>: 'static {
624    /// The datastructure that this adapter accepts during context creation.
625    type Configuration<'a>;
626    /// The datastructure that stores user state and handles adapter callbacks.
627    type Handler: ?Sized;
628}
629
630/// Represents an adapter which may be queried by name from a context.
631pub trait NamedAdapter: 'static {
632    /// The name of this adapter.
633    fn name() -> &'static str;
634}
635
636/// Stores adapter context data.
637struct AdapterContextData {
638    /// The context with which this data is associated.
639    pub ctx: *mut gvox_sys::GvoxContext,
640    /// The user data that is associated with the current context.
641    pub user_data: Option<Box<dyn Any>>,
642}
643
644/// Provides the ability to access adapter context data.
645struct AdapterContextHolder(*mut gvox_sys::GvoxAdapterContext);
646
647impl AdapterContextHolder {
648    /// Creates a new adapter context holder from the provided pointer.
649    ///
650    /// # Safety
651    ///
652    /// For this function call to be sound, the pointer must point to a valid context
653    /// that was initialized by `gvox_rs`, and no other context holder to this pointer
654    /// must exist. Further, the `gvox_rs` context must be locked for the entirety of this
655    /// holder's lifetime.
656    pub unsafe fn from_raw(ctx: *mut gvox_sys::GvoxAdapterContext) -> Self {
657        Self(ctx)
658    }
659
660    /// Retrieves a raw pointer to the underlying context, or panics if no data was associated with the provided adapter.
661    pub fn context_mut_ptr(&mut self) -> *mut gvox_sys::GvoxContext {
662        self.get_context_data()
663            .expect("No data was associated with the given adapter context.")
664            .ctx
665    }
666
667    /// Pushes a new error to the underlying context.
668    pub fn push_error(&mut self, error: GvoxError) {
669        unsafe {
670            let message = CString::new(error.message.as_str()).unwrap_or_default();
671            gvox_sys::gvox_adapter_push_error(self.0, error.error_type() as i32, message.as_ptr());
672        }
673    }
674
675    /// Applies an operation to the held user data object, or panics if the user data object type did not match.
676    pub fn user_data_operation<H: 'static>(
677        &mut self,
678        f: impl FnOnce(&mut H) -> Result<(), GvoxError>,
679    ) {
680        let mut result = Ok(());
681        if let Some(data) = self.get_user_data_holder() {
682            result = f(data
683                .downcast_mut::<H>()
684                .expect("Context user data was not of correct type."));
685        }
686
687        if let Err(error) = result {
688            self.push_error(error);
689        }
690    }
691
692    /// Retrieves a reference to holder for adapter user data.
693    pub fn get_user_data_holder(&mut self) -> &mut Option<Box<dyn Any>> {
694        &mut self
695            .get_context_data()
696            .expect("No data was associated with the given adapter context.")
697            .user_data
698    }
699
700    /// Retrieves a reference to the context's data, if it is set.
701    fn get_context_data(&mut self) -> Option<&mut AdapterContextData> {
702        unsafe {
703            let res = gvox_sys::gvox_adapter_get_user_pointer(self.0) as *mut AdapterContextData;
704            (!res.is_null()).then(|| &mut *res)
705        }
706    }
707
708    /// Sets the context data to the provided value, returning the data that was previously overwritten.
709    fn set_context_data(&mut self, data: Option<AdapterContextData>) -> Option<AdapterContextData> {
710        unsafe {
711            let res = gvox_sys::gvox_adapter_get_user_pointer(self.0) as *mut AdapterContextData;
712            gvox_sys::gvox_adapter_set_user_pointer(
713                self.0,
714                data.map(|x| Box::into_raw(Box::new(x)) as *mut c_void)
715                    .unwrap_or(std::ptr::null_mut()),
716            );
717            (!res.is_null()).then(|| *Box::from_raw(res))
718        }
719    }
720
721    /// Invokes the adapter context creation function for the given adapter type.
722    ///
723    /// # Safety
724    ///
725    /// The provided adapter context pointer must be initializable as a valid context holder,
726    /// and config must point to a valid configuration object.
727    unsafe extern "C" fn create<K: private::AdapterKindAssociation, D: AdapterDescriptor<K>>(
728        ptr: *mut gvox_sys::GvoxAdapterContext,
729        config: *const c_void,
730    ) where
731        D::Handler: BaseAdapterHandler<K, D>,
732    {
733        let mut ctx = Self::from_raw(ptr);
734        ctx.set_context_data(Some(AdapterContextData {
735            ctx: std::ptr::null_mut(),
736            user_data: None,
737        }));
738
739        match D::Handler::create(&*(config as *const D::Configuration<'_>)) {
740            Ok(value) => *ctx.get_user_data_holder() = Some(Box::new(value)),
741            Err(error) => ctx.push_error(error),
742        };
743    }
744
745    /// Invokes the adapter context deletion function for the given adapter type.
746    ///
747    /// # Safety
748    ///
749    /// The provided adapter context pointer must be initializable as a valid context holder,
750    /// and config must point to a valid configuration object.
751    unsafe extern "C" fn destroy<K: private::AdapterKindAssociation, D: AdapterDescriptor<K>>(
752        ctx: *mut gvox_sys::GvoxAdapterContext,
753    ) where
754        D::Handler: BaseAdapterHandler<K, D>,
755    {
756        let mut ctx = Self::from_raw(ctx);
757        let data = take(ctx.get_user_data_holder());
758
759        if let Some(value) = data {
760            if let Err(error) = value
761                .downcast::<D::Handler>()
762                .expect("Context user data was not of correct type.")
763                .destroy()
764            {
765                ctx.push_error(error);
766            }
767        }
768
769        ctx.set_context_data(None);
770    }
771
772    /// Invokes the adapter context blit beginning function for the given adapter type.
773    ///
774    /// # Safety
775    ///
776    /// The provided adapter context pointer must be initializable as a valid input context holder.
777    unsafe extern "C" fn blit_begin<K: private::AdapterKindAssociation, D: AdapterDescriptor<K>>(
778        blit_ctx: *mut gvox_sys::GvoxBlitContext,
779        ctx: *mut gvox_sys::GvoxAdapterContext,
780        range: *const gvox_sys::GvoxRegionRange,
781        channel_flags: u32,
782    ) where
783        D::Handler: BaseAdapterHandler<K, D>,
784    {
785        use private::*;
786
787        let mut ctx = Self::from_raw(ctx);
788        let blit_ctx = K::BlitContext::new(ctx.context_mut_ptr(), blit_ctx);
789
790        let mut_range;
791        let opt_range = if range.is_null() {
792            None
793        } else {
794            mut_range = (*range).into();
795            Some(&mut_range)
796        };
797
798        ctx.user_data_operation::<D::Handler>(|h| {
799            h.blit_begin(&blit_ctx, opt_range, channel_flags.into())
800        });
801    }
802
803    /// Invokes the adapter context blit ending function for the given adapter type.
804    ///
805    /// # Safety
806    ///
807    /// The provided adapter context pointer must be initializable as a valid input context holder.
808    unsafe extern "C" fn blit_end<K: private::AdapterKindAssociation, D: AdapterDescriptor<K>>(
809        blit_ctx: *mut gvox_sys::GvoxBlitContext,
810        ctx: *mut gvox_sys::GvoxAdapterContext,
811    ) where
812        D::Handler: BaseAdapterHandler<K, D>,
813    {
814        use private::*;
815
816        let mut ctx = Self::from_raw(ctx);
817        let blit_ctx = K::BlitContext::new(ctx.context_mut_ptr(), blit_ctx);
818
819        ctx.user_data_operation::<D::Handler>(|h| h.blit_end(&blit_ctx));
820    }
821}
822
823/// Provides the ability to access input adapter context data.
824struct InputContextHolder(AdapterContextHolder);
825
826impl InputContextHolder {
827    /// Creates a new input adapter context holder from the provided pointer.
828    ///
829    /// # Safety
830    ///
831    /// For this function call to be sound, the pointer must point to a valid input
832    /// adapter context, and all of the invariants required by `AdapterContextHolder::from_raw`
833    /// must be satisfied.
834    unsafe fn from_raw(ctx: *mut gvox_sys::GvoxAdapterContext) -> Self {
835        Self(AdapterContextHolder::from_raw(ctx))
836    }
837
838    /// Invokes the adapter context reading function for the given adapter type.
839    ///
840    /// # Safety
841    ///
842    /// The provided adapter context pointer must be initializable as a valid input context holder,
843    /// and size and data must describe a valid, writeable section of memory.
844    unsafe extern "C" fn read<D: AdapterDescriptor<Input>>(
845        ctx: *mut gvox_sys::GvoxAdapterContext,
846        position: usize,
847        size: usize,
848        data: *mut c_void,
849    ) where
850        D::Handler: InputAdapterHandler<D>,
851    {
852        let mut ctx = Self::from_raw(ctx);
853        let blit_ctx = InputBlitContext {};
854
855        ctx.0.user_data_operation::<D::Handler>(|h| {
856            h.read(
857                &blit_ctx,
858                position,
859                from_raw_parts_mut(data as *mut u8, size),
860            )
861        });
862    }
863}
864
865/// Provides the ability to access output adapter context data.
866struct OutputContextHolder(AdapterContextHolder);
867
868impl OutputContextHolder {
869    /// Creates a new output adapter context holder from the provided pointer.
870    ///
871    /// # Safety
872    ///
873    /// For this function call to be sound, the pointer must point to a valid output
874    /// adapter context, and all of the invariants required by `AdapterContextHolder::from_raw`
875    /// must be satisfied.
876    unsafe fn from_raw(ctx: *mut gvox_sys::GvoxAdapterContext) -> Self {
877        Self(AdapterContextHolder::from_raw(ctx))
878    }
879
880    /// Invokes the adapter context writing function for the given adapter type.
881    ///
882    /// # Safety
883    ///
884    /// The provided adapter context pointer must be initializable as a valid output context holder,
885    /// and size and data must describe a valid, readable section of memory.
886    unsafe extern "C" fn write<D: AdapterDescriptor<Output>>(
887        ctx: *mut gvox_sys::GvoxAdapterContext,
888        position: usize,
889        size: usize,
890        data: *const c_void,
891    ) where
892        D::Handler: OutputAdapterHandler<D>,
893    {
894        let mut ctx = Self::from_raw(ctx);
895        let blit_ctx = OutputBlitContext {};
896
897        ctx.0.user_data_operation::<D::Handler>(|h| {
898            h.write(&blit_ctx, position, from_raw_parts(data as *const u8, size))
899        });
900    }
901
902    /// Invokes the adapter context reservation function for the given adapter type.
903    ///
904    /// # Safety
905    ///
906    /// The provided adapter context pointer must be initializable as a valid output context holder.
907    unsafe extern "C" fn reserve<D: AdapterDescriptor<Output>>(
908        ctx: *mut gvox_sys::GvoxAdapterContext,
909        size: usize,
910    ) where
911        D::Handler: OutputAdapterHandler<D>,
912    {
913        let mut ctx = Self::from_raw(ctx);
914        let blit_ctx = OutputBlitContext {};
915
916        ctx.0
917            .user_data_operation::<D::Handler>(|h| h.reserve(&blit_ctx, size));
918    }
919}
920
921/// Provides the ability to access output adapter context data.
922struct ParseContextHolder(AdapterContextHolder);
923
924impl ParseContextHolder {
925    /// Creates a new parse adapter context holder from the provided pointer.
926    ///
927    /// # Safety
928    ///
929    /// For this function call to be sound, the pointer must point to a valid parse
930    /// adapter context, and all of the invariants required by `AdapterContextHolder::from_raw`
931    /// must be satisfied.
932    unsafe fn from_raw(ctx: *mut gvox_sys::GvoxAdapterContext) -> Self {
933        Self(AdapterContextHolder::from_raw(ctx))
934    }
935
936    /// Invokes the adapter details querying function for the given adapter type.
937    unsafe extern "C" fn query_details<D: AdapterDescriptor<Parse>>(
938    ) -> gvox_sys::GvoxParseAdapterDetails
939    where
940        D::Handler: ParseAdapterHandler<D>,
941    {
942        let details = D::Handler::query_details();
943        gvox_sys::GvoxParseAdapterDetails {
944            preferred_blit_mode: details.preferred_blit_mode as i32,
945        }
946    }
947
948    /// Invokes the adapter context parsable range querying function for the given adapter type.
949    ///
950    /// # Safety
951    ///
952    /// The provided adapter context pointer must be initializable as a valid parse context holder,
953    /// and size and data must describe a valid, readable section of memory.
954    unsafe extern "C" fn query_parsable_range<D: AdapterDescriptor<Parse>>(
955        blit_ctx: *mut gvox_sys::GvoxBlitContext,
956        ctx: *mut gvox_sys::GvoxAdapterContext,
957    ) -> gvox_sys::GvoxRegionRange
958    where
959        D::Handler: ParseAdapterHandler<D>,
960    {
961        use private::*;
962        let mut ctx = Self::from_raw(ctx);
963        let blit_ctx = ParseBlitContext::new(ctx.0.context_mut_ptr(), blit_ctx);
964
965        let mut res = RegionRange::default();
966        ctx.0.user_data_operation::<D::Handler>(|h| {
967            res = h.query_parsable_range(&blit_ctx);
968            Ok(())
969        });
970
971        res.into()
972    }
973
974    /// Invokes the adapter context querying function for the given adapter type.
975    ///
976    /// # Safety
977    ///
978    /// The provided adapter context pointer must be initializable as a valid parse context holder,
979    /// and size and data must describe a valid, readable section of memory.
980    unsafe extern "C" fn query_region_flags<D: AdapterDescriptor<Parse>>(
981        blit_ctx: *mut gvox_sys::GvoxBlitContext,
982        ctx: *mut gvox_sys::GvoxAdapterContext,
983        range: *const gvox_sys::GvoxRegionRange,
984        channel_flags: u32,
985    ) -> u32
986    where
987        D::Handler: ParseAdapterHandler<D>,
988    {
989        use private::*;
990
991        let mut ctx = Self::from_raw(ctx);
992        let blit_ctx = ParseBlitContext::new(ctx.0.context_mut_ptr(), blit_ctx);
993
994        let mut res = 0;
995        ctx.0.user_data_operation::<D::Handler>(|h| {
996            res = h
997                .query_region_flags(&blit_ctx, &(*range).into(), channel_flags.into())?
998                .bits();
999            Ok(())
1000        });
1001
1002        res
1003    }
1004
1005    /// Invokes the adapter context region loading function for the given adapter type.
1006    ///
1007    /// # Safety
1008    ///
1009    /// The provided adapter context pointer must be initializable as a valid parse context holder,
1010    /// and size and data must describe a valid, readable section of memory.
1011    unsafe extern "C" fn load_region<D: AdapterDescriptor<Parse>>(
1012        blit_ctx: *mut gvox_sys::GvoxBlitContext,
1013        ctx: *mut gvox_sys::GvoxAdapterContext,
1014        range: *const gvox_sys::GvoxRegionRange,
1015        channel_flags: u32,
1016    ) -> gvox_sys::GvoxRegion
1017    where
1018        D::Handler: ParseAdapterHandler<D>,
1019    {
1020        use private::*;
1021
1022        let mut ctx = Self::from_raw(ctx);
1023        let blit_ctx = ParseBlitContext::new(ctx.0.context_mut_ptr(), blit_ctx);
1024
1025        let mut res = gvox_sys::GvoxRegion {
1026            range: RegionRange::default().into(),
1027            channels: 0,
1028            flags: 0,
1029            data: std::ptr::null_mut(),
1030        };
1031        ctx.0.user_data_operation::<D::Handler>(|h| {
1032            res = h
1033                .load_region(&blit_ctx, &(*range).into(), channel_flags.into())?
1034                .into();
1035            Ok(())
1036        });
1037        res
1038    }
1039
1040    /// Invokes the adapter context region unloading function for the given adapter type.
1041    ///
1042    /// # Safety
1043    ///
1044    /// The provided adapter context pointer must be initializable as a valid parse context holder,
1045    /// and size and data must describe a valid, readable section of memory.
1046    unsafe extern "C" fn unload_region<D: AdapterDescriptor<Parse>>(
1047        blit_ctx: *mut gvox_sys::GvoxBlitContext,
1048        ctx: *mut gvox_sys::GvoxAdapterContext,
1049        region: *mut gvox_sys::GvoxRegion,
1050    ) where
1051        D::Handler: ParseAdapterHandler<D>,
1052    {
1053        use private::*;
1054
1055        let mut ctx = Self::from_raw(ctx);
1056        let blit_ctx = ParseBlitContext::new(ctx.0.context_mut_ptr(), blit_ctx);
1057
1058        ctx.0
1059            .user_data_operation::<D::Handler>(|h| h.unload_region(&blit_ctx, transmute(*region)));
1060        (*region).range = RegionRange::default().into();
1061    }
1062
1063    /// Invokes the adapter context region sampling function for the given adapter type.
1064    ///
1065    /// # Safety
1066    ///
1067    /// The provided adapter context pointer must be initializable as a valid parse context holder,
1068    /// and size and data must describe a valid, readable section of memory.
1069    unsafe extern "C" fn sample_region<D: AdapterDescriptor<Parse>>(
1070        blit_ctx: *mut gvox_sys::GvoxBlitContext,
1071        ctx: *mut gvox_sys::GvoxAdapterContext,
1072        region: *const gvox_sys::GvoxRegion,
1073        offset: *const gvox_sys::GvoxOffset3D,
1074        channel_id: u32,
1075    ) -> gvox_sys::GvoxSample
1076    where
1077        D::Handler: ParseAdapterHandler<D>,
1078    {
1079        use private::*;
1080
1081        let mut ctx = Self::from_raw(ctx);
1082        let blit_ctx = ParseBlitContext::new(ctx.0.context_mut_ptr(), blit_ctx);
1083
1084        let mut res = Sample {
1085            data: 0,
1086            is_present: false,
1087        };
1088        ctx.0.user_data_operation::<D::Handler>(|h| {
1089            res = h.sample_region(
1090                &blit_ctx,
1091                &*transmute::<_, *const Region<<D::Handler as ParseAdapterHandler<D>>::RegionData>>(
1092                    region,
1093                ),
1094                &(*offset).into(),
1095                ChannelId::try_from(channel_id)?,
1096            )?;
1097            Ok(())
1098        });
1099        gvox_sys::GvoxSample {
1100            data: res.data,
1101            is_present: res.is_present as u8,
1102        }
1103    }
1104
1105    unsafe extern "C" fn parse_region<D: AdapterDescriptor<Parse>>(
1106        blit_ctx: *mut gvox_sys::GvoxBlitContext,
1107        ctx: *mut gvox_sys::GvoxAdapterContext,
1108        range: *const gvox_sys::GvoxRegionRange,
1109        channel_flags: u32,
1110    ) where
1111        D::Handler: ParseAdapterHandler<D>,
1112    {
1113        use private::*;
1114
1115        let mut ctx = Self::from_raw(ctx);
1116        let blit_ctx = ParseBlitContext::new(ctx.0.context_mut_ptr(), blit_ctx);
1117
1118        ctx.0.user_data_operation::<D::Handler>(|h| {
1119            h.parse_region(&blit_ctx, &(*range).into(), channel_flags.into())
1120        });
1121    }
1122}
1123
1124/// Provides the ability to access output adapter context data.
1125struct SerializeContextHolder(AdapterContextHolder);
1126
1127impl SerializeContextHolder {
1128    /// Creates a new serialize adapter context holder from the provided pointer.
1129    ///
1130    /// # Safety
1131    ///
1132    /// For this function call to be sound, the pointer must point to a valid parse
1133    /// adapter context, and all of the invariants required by `AdapterContextHolder::from_raw`
1134    /// must be satisfied.
1135    unsafe fn from_raw(ctx: *mut gvox_sys::GvoxAdapterContext) -> Self {
1136        Self(AdapterContextHolder::from_raw(ctx))
1137    }
1138
1139    /// Invokes the adapter context writing function for the given adapter type.
1140    ///
1141    /// # Safety
1142    ///
1143    /// The provided adapter context pointer must be initializable as a valid serialize context holder,
1144    /// and size and data must describe a valid, readable section of memory.
1145    unsafe extern "C" fn serialize_region<D: AdapterDescriptor<Serialize>>(
1146        blit_ctx: *mut gvox_sys::GvoxBlitContext,
1147        ctx: *mut gvox_sys::GvoxAdapterContext,
1148        range: *const gvox_sys::GvoxRegionRange,
1149        channel_flags: u32,
1150    ) where
1151        D::Handler: SerializeAdapterHandler<D>,
1152    {
1153        use private::*;
1154
1155        let mut ctx = Self::from_raw(ctx);
1156        let blit_ctx = SerializeBlitContext::new(ctx.0.context_mut_ptr(), blit_ctx);
1157
1158        ctx.0.user_data_operation::<D::Handler>(|h| {
1159            h.serialize_region(
1160                &blit_ctx,
1161                &(*range).into(),
1162                ChannelFlags::from(channel_flags),
1163            )
1164        });
1165    }
1166
1167    /// Invokes the adapter context receiving function for the given adapter type.
1168    ///
1169    /// # Safety
1170    ///
1171    /// The provided adapter context pointer must be initializable as a valid serialize context holder,
1172    /// and size and data must describe a valid, readable section of memory.
1173    unsafe extern "C" fn receive_region<D: AdapterDescriptor<Serialize>>(
1174        blit_ctx: *mut gvox_sys::GvoxBlitContext,
1175        ctx: *mut gvox_sys::GvoxAdapterContext,
1176        region: *const gvox_sys::GvoxRegion,
1177    ) where
1178        D::Handler: SerializeAdapterHandler<D>,
1179    {
1180        use private::*;
1181
1182        let mut ctx = Self::from_raw(ctx);
1183        let blit_ctx = SerializeBlitContext::new(ctx.0.context_mut_ptr(), blit_ctx);
1184
1185        let region_ref = RegionRef {
1186            blit_ctx: &blit_ctx,
1187            region: *region,
1188        };
1189
1190        ctx.0
1191            .user_data_operation::<D::Handler>(|h| h.receive_region(&blit_ctx, &region_ref));
1192
1193        std::mem::forget(region_ref);
1194    }
1195}
1196
1197/// Provides the ability for an input adapter to interact with other adapters during blit operations.
1198pub struct InputBlitContext {}
1199
1200/// Provides the ability for an output adapter to interact with other adapters during blit operations.
1201pub struct OutputBlitContext {}
1202
1203/// Provides the ability for a parse adapter to interact with other adapters during blit operations.
1204pub struct ParseBlitContext {
1205    /// A pointer to the underlying blit context.
1206    blit_ctx: *mut gvox_sys::GvoxBlitContext,
1207    /// A pointer to the underlying context.
1208    ctx: *mut gvox_sys::GvoxContext,
1209}
1210
1211impl ParseBlitContext {
1212    /// Reads data from the input adapter into the provided slice, starting at the provided source position.
1213    pub fn input_read(&self, position: usize, data: &mut [u8]) -> Result<(), GvoxError> {
1214        unsafe {
1215            gvox_sys::gvox_input_read(
1216                self.blit_ctx,
1217                position,
1218                data.len(),
1219                data.as_mut_ptr() as *mut c_void,
1220            );
1221            ContextInner::get_error_from_raw_ptr(self.ctx)
1222        }
1223    }
1224
1225    /// Supplies a parsable region directly to the serialize adapter, meant to only be called from parse_region
1226    pub fn emit_region<T>(&self, region: &Region<T>) -> Result<(), GvoxError> {
1227        unsafe {
1228            gvox_sys::gvox_emit_region(
1229                self.blit_ctx,
1230                region as *const Region<T> as *const gvox_sys::GvoxRegion,
1231            );
1232            ContextInner::get_error_from_raw_ptr(self.ctx)
1233        }
1234    }
1235}
1236
1237/// Provides the ability for a serialize adapter to interact with other adapters during blit operations.
1238pub struct SerializeBlitContext {
1239    /// A pointer to the underlying blit context.
1240    blit_ctx: *mut gvox_sys::GvoxBlitContext,
1241    /// A pointer to the underlying context.
1242    ctx: *mut gvox_sys::GvoxContext,
1243}
1244
1245impl SerializeBlitContext {
1246    /// Determines the flags that all voxels in the given region share.
1247    pub fn query_region_flags(
1248        &self,
1249        range: &RegionRange,
1250        channel_flags: ChannelFlags,
1251    ) -> Result<RegionFlags, GvoxError> {
1252        unsafe {
1253            let flags = gvox_sys::gvox_query_region_flags(
1254                self.blit_ctx,
1255                range as *const RegionRange as *const gvox_sys::GvoxRegionRange,
1256                channel_flags.into(),
1257            );
1258            ContextInner::get_error_from_raw_ptr(self.ctx)
1259                .map(|()| RegionFlags::from_bits_truncate(flags))
1260        }
1261    }
1262
1263    /// Loads the provided region of voxels from the parse adapter.
1264    pub fn load_region_range<'a>(
1265        &'a self,
1266        range: &RegionRange,
1267        channel_flags: ChannelFlags,
1268    ) -> Result<RegionRef<'a>, GvoxError> {
1269        unsafe {
1270            let region = gvox_sys::gvox_load_region_range(
1271                self.blit_ctx,
1272                &(*range).into(),
1273                channel_flags.into(),
1274            );
1275            ContextInner::get_error_from_raw_ptr(self.ctx).map(|()| RegionRef {
1276                blit_ctx: self,
1277                region,
1278            })
1279        }
1280    }
1281
1282    /// Writes the given slice of bytes to the output adapter at the provided position.
1283    pub fn output_write(&self, position: usize, data: &[u8]) -> Result<(), GvoxError> {
1284        unsafe {
1285            gvox_sys::gvox_output_write(
1286                self.blit_ctx,
1287                position,
1288                data.len(),
1289                data.as_ptr() as *const c_void,
1290            );
1291            ContextInner::get_error_from_raw_ptr(self.ctx)
1292        }
1293    }
1294
1295    /// Hints that the output adapter should make room for at least the given number of bytes.
1296    pub fn output_reserve(&self, size: usize) -> Result<(), GvoxError> {
1297        unsafe {
1298            gvox_sys::gvox_output_reserve(self.blit_ctx, size);
1299            ContextInner::get_error_from_raw_ptr(self.ctx)
1300        }
1301    }
1302}
1303
1304/// Represents the user data type that handles adapter context operations.
1305pub trait BaseAdapterHandler<
1306    K: AdapterKind + private::AdapterKindAssociation,
1307    D: AdapterDescriptor<K, Handler = Self>,
1308>: 'static + Sized
1309{
1310    /// Creates a new adapter context handler with the supplied configuration.
1311    fn create(config: &D::Configuration<'_>) -> Result<Self, GvoxError>;
1312    /// Destroys the provided adapter context handler.
1313    fn destroy(self) -> Result<(), GvoxError>;
1314
1315    /// Called whenever a blit operation begins for the current context.
1316    fn blit_begin(
1317        &mut self,
1318        _: &K::BlitContext,
1319        _: Option<&RegionRange>,
1320        _: ChannelFlags,
1321    ) -> Result<(), GvoxError> {
1322        Ok(())
1323    }
1324    /// Called whenever a blit operation ends for the current context.
1325    fn blit_end(&mut self, _: &K::BlitContext) -> Result<(), GvoxError> {
1326        Ok(())
1327    }
1328}
1329
1330/// Represents the user data type that handles input adapter context operations.
1331pub trait InputAdapterHandler<D: AdapterDescriptor<Input, Handler = Self>>:
1332    BaseAdapterHandler<Input, D>
1333{
1334    /// Fills the provided data slice with bytes from this input adapter, beginning at the specified source offset.
1335    fn read(
1336        &mut self,
1337        blit_ctx: &InputBlitContext,
1338        position: usize,
1339        data: &mut [u8],
1340    ) -> Result<(), GvoxError>;
1341}
1342
1343/// Represents the user data type that handles output adapter context operations.
1344pub trait OutputAdapterHandler<D: AdapterDescriptor<Output, Handler = Self>>:
1345    BaseAdapterHandler<Output, D>
1346{
1347    /// Writes the provided data slice to this output adapter, beginning at the specified target offset.
1348    fn write(
1349        &mut self,
1350        blit_ctx: &OutputBlitContext,
1351        position: usize,
1352        data: &[u8],
1353    ) -> Result<(), GvoxError>;
1354    /// Hints that the adapter should expect to have at least the given number of total bytes written to it.
1355    fn reserve(&mut self, blit_ctx: &OutputBlitContext, size: usize) -> Result<(), GvoxError>;
1356}
1357
1358/// Represents the user data type that handles parse adapter context operations.
1359pub trait ParseAdapterHandler<D: AdapterDescriptor<Parse, Handler = Self>>:
1360    BaseAdapterHandler<Parse, D>
1361{
1362    /// The loaded data associated with a given region of voxels.
1363    type RegionData;
1364
1365    /// Provides the adapter-wide information, such as whether the adapter prefers to blit as parse-driven or as serialize-driven.
1366    fn query_details() -> ParseAdapterDetails;
1367    /// After the parse adapter has had blit_begin called, this will provide the offset and extent of the parsable range of the given input.
1368    fn query_parsable_range(&mut self, blit_ctx: &ParseBlitContext) -> RegionRange;
1369    /// Determines the flags that all voxels in the given region share.
1370    fn query_region_flags(
1371        &mut self,
1372        blit_ctx: &ParseBlitContext,
1373        range: &RegionRange,
1374        channel_flags: ChannelFlags,
1375    ) -> Result<RegionFlags, GvoxError>;
1376    /// Loads the channel data for the given region of voxels.
1377    fn load_region(
1378        &mut self,
1379        blit_ctx: &ParseBlitContext,
1380        range: &RegionRange,
1381        channel_flags: ChannelFlags,
1382    ) -> Result<Region<Self::RegionData>, GvoxError>;
1383    /// Unloads the previously-created region of voxels.
1384    fn unload_region(
1385        &mut self,
1386        blit_ctx: &ParseBlitContext,
1387        region: Region<Self::RegionData>,
1388    ) -> Result<(), GvoxError>;
1389    /// Determines the value of a voxel at the provided sample position.
1390    fn sample_region(
1391        &mut self,
1392        blit_ctx: &ParseBlitContext,
1393        region: &Region<Self::RegionData>,
1394        offset: &Offset3D,
1395        channel_id: ChannelId,
1396    ) -> Result<Sample, GvoxError>;
1397    /// Called when in parse-driven mode, to parse the entire requested range, emitting sample-able regions to be handled by the serialize adapter.
1398    fn parse_region(
1399        &mut self,
1400        blit_ctx: &ParseBlitContext,
1401        range: &RegionRange,
1402        channel_flags: ChannelFlags,
1403    ) -> Result<(), GvoxError>;
1404}
1405
1406/// Represents the user data type that handles serialize adapter context operations.
1407pub trait SerializeAdapterHandler<D: AdapterDescriptor<Serialize, Handler = Self>>:
1408    BaseAdapterHandler<Serialize, D>
1409{
1410    /// The loaded data associated with a given region of voxels.
1411    type RegionData;
1412
1413    /// Serializes the provided range of voxels to the output stream.
1414    fn serialize_region(
1415        &mut self,
1416        blit_ctx: &SerializeBlitContext,
1417        range: &RegionRange,
1418        channel_flags: ChannelFlags,
1419    ) -> Result<(), GvoxError>;
1420
1421    /// Serializes the provided range of voxels to the output stream.
1422    fn receive_region(
1423        &mut self,
1424        blit_ctx: &SerializeBlitContext,
1425        region: &RegionRef<'_>,
1426    ) -> Result<(), GvoxError>;
1427}
1428
1429/// Stores data about the loaded state of a provided region of voxels.
1430#[derive(Clone, Debug, Default)]
1431#[repr(C)]
1432pub struct Region<T> {
1433    /// The range of loaded voxels.
1434    pub range: RegionRange,
1435    /// The channels that have been loaded.
1436    pub channels: ChannelFlags,
1437    /// The flags of the region.
1438    pub flags: RegionFlags,
1439    /// The user data associated with this region.
1440    data: Box<T>,
1441}
1442
1443impl<T> Region<T> {
1444    /// Creates a new region for the provided range, channels, flags, and user data.
1445    pub fn new(range: RegionRange, channels: ChannelFlags, flags: RegionFlags, data: T) -> Self {
1446        let data = Box::new(data);
1447        Self {
1448            range,
1449            channels,
1450            flags,
1451            data,
1452        }
1453    }
1454}
1455
1456impl<T> Deref for Region<T> {
1457    type Target = T;
1458
1459    fn deref(&self) -> &Self::Target {
1460        &self.data
1461    }
1462}
1463
1464impl<T> DerefMut for Region<T> {
1465    fn deref_mut(&mut self) -> &mut Self::Target {
1466        &mut self.data
1467    }
1468}
1469
1470impl<T> From<Region<T>> for gvox_sys::GvoxRegion {
1471    fn from(value: Region<T>) -> Self {
1472        unsafe { transmute(value) }
1473    }
1474}
1475
1476/// Describes a region of voxels and provides the ability to sample from it.
1477pub struct RegionRef<'a> {
1478    /// A reference to the blit context that was utilized to create this region.
1479    blit_ctx: &'a SerializeBlitContext,
1480    /// The region of loaded voxels.
1481    region: gvox_sys::GvoxRegion,
1482}
1483
1484impl<'a> RegionRef<'a> {
1485    /// The set of channels that are available for this region.
1486    pub fn channels(&self) -> ChannelFlags {
1487        ChannelFlags::from(self.region.channels)
1488    }
1489
1490    /// The flags associated with this region.
1491    pub fn flags(&self) -> RegionFlags {
1492        RegionFlags::from_bits_truncate(self.region.flags)
1493    }
1494
1495    /// The 3D range of voxels that this region spans.
1496    pub fn range(&self) -> RegionRange {
1497        self.region.range.into()
1498    }
1499
1500    /// Samples the channel value of the voxel at the provided position.
1501    pub fn sample(&self, offset: &Offset3D, channel_id: ChannelId) -> Result<Sample, GvoxError> {
1502        unsafe {
1503            let res = gvox_sys::gvox_sample_region(
1504                self.blit_ctx.blit_ctx,
1505                &self.region as *const gvox_sys::GvoxRegion as *mut gvox_sys::GvoxRegion,
1506                &(*offset).into(),
1507                channel_id.into(),
1508            );
1509            ContextInner::get_error_from_raw_ptr(self.blit_ctx.ctx).map(|()| Sample {
1510                data: res.data,
1511                is_present: res.is_present != 0,
1512            })
1513        }
1514    }
1515}
1516
1517impl<'a> Drop for RegionRef<'a> {
1518    fn drop(&mut self) {
1519        unsafe {
1520            gvox_sys::gvox_unload_region_range(
1521                self.blit_ctx.blit_ctx,
1522                &mut self.region,
1523                &self.region.range,
1524            );
1525        }
1526    }
1527}
1528
1529/// Represents an offset on a 3D grid.
1530#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
1531#[repr(C)]
1532pub struct Offset3D {
1533    /// The x-component of the offset.
1534    pub x: i32,
1535    /// The y-component of the offset.
1536    pub y: i32,
1537    /// The z-component of the offset.
1538    pub z: i32,
1539}
1540
1541impl From<gvox_sys::GvoxOffset3D> for Offset3D {
1542    fn from(value: gvox_sys::GvoxOffset3D) -> Self {
1543        let gvox_sys::GvoxOffset3D { x, y, z } = value;
1544        Self { x, y, z }
1545    }
1546}
1547
1548impl From<Offset3D> for gvox_sys::GvoxOffset3D {
1549    fn from(value: Offset3D) -> Self {
1550        let Offset3D { x, y, z } = value;
1551        Self { x, y, z }
1552    }
1553}
1554
1555/// Represents the dimensions of a volume on a 3D grid.
1556#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
1557#[repr(C)]
1558pub struct Extent3D {
1559    /// The x-length of the dimensions.
1560    pub x: u32,
1561    /// The y-length of the dimensions.
1562    pub y: u32,
1563    /// The z-length of the dimensions.
1564    pub z: u32,
1565}
1566
1567impl From<gvox_sys::GvoxExtent3D> for Extent3D {
1568    fn from(value: gvox_sys::GvoxExtent3D) -> Self {
1569        let gvox_sys::GvoxExtent3D { x, y, z } = value;
1570        Self { x, y, z }
1571    }
1572}
1573
1574impl From<Extent3D> for gvox_sys::GvoxExtent3D {
1575    fn from(value: Extent3D) -> Self {
1576        let Extent3D { x, y, z } = value;
1577        Self { x, y, z }
1578    }
1579}
1580
1581/// Represents a volume on a 3D grid.
1582#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
1583#[repr(C)]
1584pub struct RegionRange {
1585    /// The position of the minimum corner of the region.
1586    pub offset: Offset3D,
1587    /// The dimensions of the region.
1588    pub extent: Extent3D,
1589}
1590
1591impl From<gvox_sys::GvoxRegionRange> for RegionRange {
1592    fn from(value: gvox_sys::GvoxRegionRange) -> Self {
1593        Self {
1594            offset: value.offset.into(),
1595            extent: value.extent.into(),
1596        }
1597    }
1598}
1599
1600impl From<RegionRange> for gvox_sys::GvoxRegionRange {
1601    fn from(value: RegionRange) -> Self {
1602        Self {
1603            offset: value.offset.into(),
1604            extent: value.extent.into(),
1605        }
1606    }
1607}
1608
1609/// Describes the type of error that occurred during voxel conversion operations.
1610#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1611#[repr(i32)]
1612pub enum ErrorType {
1613    /// There is no information associated with this error type.
1614    Unknown = gvox_sys::GvoxResult_GVOX_RESULT_ERROR_UNKNOWN,
1615    /// A supplied parameter was invalid.
1616    InvalidParameter = gvox_sys::GvoxResult_GVOX_RESULT_ERROR_INVALID_PARAMETER,
1617    /// An issue occurred with an input adapter.
1618    InputAdapter = gvox_sys::GvoxResult_GVOX_RESULT_ERROR_INPUT_ADAPTER,
1619    /// An issue occurred with an output adapter.
1620    OutputAdapter = gvox_sys::GvoxResult_GVOX_RESULT_ERROR_OUTPUT_ADAPTER,
1621    /// An issue occurred with a parse adapter.
1622    ParseAdapter = gvox_sys::GvoxResult_GVOX_RESULT_ERROR_PARSE_ADAPTER,
1623    /// An issue occurred with a serialize adapter.
1624    SerializeAdapter = gvox_sys::GvoxResult_GVOX_RESULT_ERROR_SERIALIZE_ADAPTER,
1625    /// A parse adapter was provided invalid input.
1626    ParseAdapterInvalidInput = gvox_sys::GvoxResult_GVOX_RESULT_ERROR_PARSE_ADAPTER_INVALID_INPUT,
1627    /// A voxel channel was not available for a parse adapter to read.
1628    ParseAdapterRequestedChannelNotPresent =
1629        gvox_sys::GvoxResult_GVOX_RESULT_ERROR_PARSE_ADAPTER_REQUESTED_CHANNEL_NOT_PRESENT,
1630    /// A serialize adapter's format did not support the output data type.
1631    SerializeAdapterUnrepresentableData =
1632        gvox_sys::GvoxResult_GVOX_RESULT_ERROR_SERIALIZE_ADAPTER_UNREPRESENTABLE_DATA,
1633}
1634
1635impl From<i32> for ErrorType {
1636    fn from(value: i32) -> Self {
1637        match value {
1638            gvox_sys::GvoxResult_GVOX_RESULT_ERROR_UNKNOWN => Self::Unknown,
1639            gvox_sys::GvoxResult_GVOX_RESULT_ERROR_INVALID_PARAMETER => Self::InvalidParameter,
1640            gvox_sys::GvoxResult_GVOX_RESULT_ERROR_INPUT_ADAPTER => Self::InputAdapter,
1641            gvox_sys::GvoxResult_GVOX_RESULT_ERROR_OUTPUT_ADAPTER => Self::OutputAdapter,
1642            gvox_sys::GvoxResult_GVOX_RESULT_ERROR_PARSE_ADAPTER => Self::ParseAdapter,
1643            gvox_sys::GvoxResult_GVOX_RESULT_ERROR_SERIALIZE_ADAPTER => Self::SerializeAdapter,
1644            gvox_sys::GvoxResult_GVOX_RESULT_ERROR_PARSE_ADAPTER_INVALID_INPUT => Self::ParseAdapterInvalidInput,
1645            gvox_sys::GvoxResult_GVOX_RESULT_ERROR_PARSE_ADAPTER_REQUESTED_CHANNEL_NOT_PRESENT => Self::ParseAdapterRequestedChannelNotPresent,
1646            gvox_sys::GvoxResult_GVOX_RESULT_ERROR_SERIALIZE_ADAPTER_UNREPRESENTABLE_DATA => Self::SerializeAdapterUnrepresentableData,
1647            _ => Self::Unknown
1648        }
1649    }
1650}
1651
1652/// Describes the blit mode of voxel conversion operations.
1653#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1654#[repr(i32)]
1655pub enum BlitMode {
1656    /// The adapter does not care how it's blit
1657    DontCare = gvox_sys::GvoxBlitMode_GVOX_BLIT_MODE_DONT_CARE,
1658    /// The adapter prefers to be blit parse-driven
1659    ParseDriven = gvox_sys::GvoxBlitMode_GVOX_BLIT_MODE_PARSE_DRIVEN,
1660    /// The adapter prefers to be blit serialize-driven
1661    SerializeDriven = gvox_sys::GvoxBlitMode_GVOX_BLIT_MODE_SERIALIZE_DRIVEN,
1662}
1663
1664/// Describes basic info about a parse adapter
1665#[derive(Clone, Debug)]
1666pub struct ParseAdapterDetails {
1667    /// Allows the adapter to configure which blit mode to use, if using the default blit function
1668    preferred_blit_mode: BlitMode,
1669}
1670
1671/// Describes an error that occurred during voxel conversion operations.
1672#[derive(Clone, Debug)]
1673pub struct GvoxError {
1674    /// The type of error that occurred.
1675    ty: ErrorType,
1676    /// The message describing the error.
1677    message: String,
1678}
1679
1680impl GvoxError {
1681    /// Creates a new error with the provided type and reason message.
1682    pub fn new(ty: ErrorType, message: impl Into<String>) -> Self {
1683        let message = Into::<String>::into(message);
1684        Self { ty, message }
1685    }
1686
1687    /// The type of error that occurred.
1688    pub fn error_type(&self) -> ErrorType {
1689        self.ty
1690    }
1691}
1692
1693impl Error for GvoxError {
1694    fn description(&self) -> &str {
1695        &self.message
1696    }
1697}
1698
1699impl std::fmt::Display for GvoxError {
1700    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1701        f.write_fmt(format_args!("{:?}: {}", self.ty, self.message))
1702    }
1703}
1704
1705/// Describes a sample that is supplied by the parse adapter.
1706pub struct Sample {
1707    pub data: u32,
1708    pub is_present: bool,
1709}
1710
1711/// Identifies a specific property associated with a voxel volume.
1712#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1713pub struct ChannelId(u32);
1714
1715impl ChannelId {
1716    /// The color of voxels.
1717    pub const COLOR: Self = Self(gvox_sys::GVOX_CHANNEL_ID_COLOR);
1718    /// The normal vector of voxels.
1719    pub const NORMAL: Self = Self(gvox_sys::GVOX_CHANNEL_ID_NORMAL);
1720    /// The material IDs of voxels.
1721    pub const MATERIAL_ID: Self = Self(gvox_sys::GVOX_CHANNEL_ID_MATERIAL_ID);
1722    /// The roughness coefficient of voxels.
1723    pub const ROUGHNESS: Self = Self(gvox_sys::GVOX_CHANNEL_ID_ROUGHNESS);
1724    /// The metalness coefficient of voxels.
1725    pub const METALNESS: Self = Self(gvox_sys::GVOX_CHANNEL_ID_METALNESS);
1726    /// The alpha value of volumes.
1727    pub const TRANSPARENCY: Self = Self(gvox_sys::GVOX_CHANNEL_ID_TRANSPARENCY);
1728    /// The IOR coefficient of voxels.
1729    pub const IOR: Self = Self(gvox_sys::GVOX_CHANNEL_ID_IOR);
1730    /// The emissive color of voxels.
1731    pub const EMISSIVE_COLOR: Self = Self(gvox_sys::GVOX_CHANNEL_ID_EMISSIVITY);
1732    /// The hardness coefficient of voxels.
1733    pub const HARDNESS: Self = Self(gvox_sys::GVOX_CHANNEL_ID_HARDNESS);
1734
1735    /// Retrieves an iterator over all voxel channel IDs.
1736    pub fn iter() -> impl Iterator<Item = ChannelId> {
1737        (0..=gvox_sys::GVOX_CHANNEL_ID_LAST).map(ChannelId)
1738    }
1739}
1740
1741impl TryFrom<u32> for ChannelId {
1742    type Error = GvoxError;
1743
1744    fn try_from(value: u32) -> Result<Self, Self::Error> {
1745        (value <= gvox_sys::GVOX_CHANNEL_ID_LAST)
1746            .then_some(Self(value))
1747            .ok_or_else(|| {
1748                GvoxError::new(
1749                    ErrorType::InvalidParameter,
1750                    format!("Channel ID {value} is out of range 0..=31."),
1751                )
1752            })
1753    }
1754}
1755
1756impl From<ChannelId> for u32 {
1757    fn from(value: ChannelId) -> Self {
1758        value.0
1759    }
1760}
1761
1762impl BitAnd for ChannelId {
1763    type Output = ChannelFlags;
1764
1765    fn bitand(self, rhs: Self) -> Self::Output {
1766        ChannelFlags::from(self) & rhs
1767    }
1768}
1769
1770impl BitOr for ChannelId {
1771    type Output = ChannelFlags;
1772
1773    fn bitor(self, rhs: Self) -> Self::Output {
1774        ChannelFlags::from(self) | rhs
1775    }
1776}
1777
1778impl BitXor for ChannelId {
1779    type Output = ChannelFlags;
1780
1781    fn bitxor(self, rhs: Self) -> Self::Output {
1782        ChannelFlags::from(self) ^ rhs
1783    }
1784}
1785
1786impl BitAnd<ChannelFlags> for ChannelId {
1787    type Output = ChannelFlags;
1788
1789    fn bitand(self, rhs: ChannelFlags) -> Self::Output {
1790        ChannelFlags::from(self) & rhs
1791    }
1792}
1793
1794impl BitOr<ChannelFlags> for ChannelId {
1795    type Output = ChannelFlags;
1796
1797    fn bitor(self, rhs: ChannelFlags) -> Self::Output {
1798        ChannelFlags::from(self) | rhs
1799    }
1800}
1801
1802impl BitXor<ChannelFlags> for ChannelId {
1803    type Output = ChannelFlags;
1804
1805    fn bitxor(self, rhs: ChannelFlags) -> Self::Output {
1806        ChannelFlags::from(self) ^ rhs
1807    }
1808}
1809
1810/// A set of binary flags which denotes a collection of channel IDs.
1811#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
1812pub struct ChannelFlags(u32);
1813
1814impl ChannelFlags {
1815    /// Provides a set of flags that contains all possible channel IDs.
1816    pub const fn all() -> Self {
1817        Self(u32::MAX)
1818    }
1819
1820    /// Returns whether the provided channel is contained in this ID set.
1821    pub fn contains(&self, x: ChannelId) -> bool {
1822        (self.0 & (1 << u32::from(x))) != 0
1823    }
1824
1825    /// Provides a set of flags that contains no channel IDs.
1826    pub const fn empty() -> Self {
1827        Self(0)
1828    }
1829}
1830
1831impl IntoIterator for ChannelFlags {
1832    type Item = ChannelId;
1833
1834    type IntoIter = Box<dyn Iterator<Item = Self::Item>>;
1835
1836    fn into_iter(self) -> Self::IntoIter {
1837        Box::new(ChannelId::iter().filter(move |&x| self.contains(x)))
1838    }
1839}
1840
1841impl From<ChannelId> for ChannelFlags {
1842    fn from(value: ChannelId) -> Self {
1843        Self(1 << value.0)
1844    }
1845}
1846
1847impl From<ChannelFlags> for u32 {
1848    fn from(value: ChannelFlags) -> Self {
1849        value.0
1850    }
1851}
1852
1853impl From<u32> for ChannelFlags {
1854    fn from(value: u32) -> Self {
1855        Self(value)
1856    }
1857}
1858
1859impl Not for ChannelFlags {
1860    type Output = Self;
1861
1862    fn not(self) -> Self::Output {
1863        Self(!self.0)
1864    }
1865}
1866
1867impl BitAnd for ChannelFlags {
1868    type Output = Self;
1869
1870    fn bitand(self, rhs: Self) -> Self::Output {
1871        Self(self.0 & rhs.0)
1872    }
1873}
1874
1875impl BitAndAssign for ChannelFlags {
1876    fn bitand_assign(&mut self, rhs: Self) {
1877        *self = *self & ChannelFlags::from(rhs);
1878    }
1879}
1880
1881impl BitOr for ChannelFlags {
1882    type Output = Self;
1883
1884    fn bitor(self, rhs: Self) -> Self::Output {
1885        Self(self.0 | ChannelFlags::from(rhs).0)
1886    }
1887}
1888
1889impl BitOrAssign for ChannelFlags {
1890    fn bitor_assign(&mut self, rhs: Self) {
1891        *self = *self | ChannelFlags::from(rhs);
1892    }
1893}
1894
1895impl BitXor for ChannelFlags {
1896    type Output = Self;
1897
1898    fn bitxor(self, rhs: Self) -> Self::Output {
1899        Self(self.0 ^ ChannelFlags::from(rhs).0)
1900    }
1901}
1902
1903impl BitXorAssign for ChannelFlags {
1904    fn bitxor_assign(&mut self, rhs: Self) {
1905        *self = *self ^ rhs;
1906    }
1907}
1908
1909impl BitAnd<ChannelId> for ChannelFlags {
1910    type Output = Self;
1911
1912    fn bitand(self, rhs: ChannelId) -> Self::Output {
1913        Self(self.0 & ChannelFlags::from(rhs).0)
1914    }
1915}
1916
1917impl BitAndAssign<ChannelId> for ChannelFlags {
1918    fn bitand_assign(&mut self, rhs: ChannelId) {
1919        *self = *self & ChannelFlags::from(rhs);
1920    }
1921}
1922
1923impl BitOr<ChannelId> for ChannelFlags {
1924    type Output = Self;
1925
1926    fn bitor(self, rhs: ChannelId) -> Self::Output {
1927        Self(self.0 | ChannelFlags::from(rhs).0)
1928    }
1929}
1930
1931impl BitOrAssign<ChannelId> for ChannelFlags {
1932    fn bitor_assign(&mut self, rhs: ChannelId) {
1933        *self = *self | ChannelFlags::from(rhs);
1934    }
1935}
1936
1937impl BitXor<ChannelId> for ChannelFlags {
1938    type Output = Self;
1939
1940    fn bitxor(self, rhs: ChannelId) -> Self::Output {
1941        Self(self.0 ^ ChannelFlags::from(rhs).0)
1942    }
1943}
1944
1945impl BitXorAssign<ChannelId> for ChannelFlags {
1946    fn bitxor_assign(&mut self, rhs: ChannelId) {
1947        *self = *self ^ ChannelFlags::from(rhs);
1948    }
1949}
1950
1951bitflags! {
1952    /// Describes the group properties of a voxel region.
1953    pub struct RegionFlags: u32 {
1954        /// The given channel set has the same value over the entirety of the region.
1955        const UNIFORM = gvox_sys::GVOX_REGION_FLAG_UNIFORM;
1956    }
1957}
1958
1959impl Default for RegionFlags {
1960    fn default() -> Self {
1961        Self::empty()
1962    }
1963}
1964
1965/// Private module utilized to hide private, externally-unimplementable traits.
1966mod private {
1967    use super::*;
1968
1969    /// A trait which cannot be implemented from external crates, preventing end users
1970    /// from implementing subtraits for their own types.
1971    pub trait Sealed {}
1972
1973    impl Sealed for Input {}
1974    impl Sealed for Output {}
1975    impl Sealed for Parse {}
1976    impl Sealed for Serialize {}
1977
1978    /// Provides an interface through which adapters can query other adapters for information.
1979    pub trait BlitContextType: 'static + Sized {
1980        /// Creates a new blit context for the given context and blit pointers.
1981        ///
1982        /// # Safety
1983        ///
1984        /// For this function call to be sound, both parameters must point to valid contexts
1985        /// and this object must not outlive either of them.
1986        unsafe fn new(
1987            ctx: *mut gvox_sys::GvoxContext,
1988            blit_ctx: *mut gvox_sys::GvoxBlitContext,
1989        ) -> Self;
1990    }
1991
1992    impl BlitContextType for InputBlitContext {
1993        unsafe fn new(_: *mut gvox_sys::GvoxContext, _: *mut gvox_sys::GvoxBlitContext) -> Self {
1994            Self {}
1995        }
1996    }
1997
1998    impl BlitContextType for OutputBlitContext {
1999        unsafe fn new(_: *mut gvox_sys::GvoxContext, _: *mut gvox_sys::GvoxBlitContext) -> Self {
2000            Self {}
2001        }
2002    }
2003
2004    impl BlitContextType for ParseBlitContext {
2005        unsafe fn new(
2006            ctx: *mut gvox_sys::GvoxContext,
2007            blit_ctx: *mut gvox_sys::GvoxBlitContext,
2008        ) -> Self {
2009            Self { blit_ctx, ctx }
2010        }
2011    }
2012
2013    impl BlitContextType for SerializeBlitContext {
2014        unsafe fn new(
2015            ctx: *mut gvox_sys::GvoxContext,
2016            blit_ctx: *mut gvox_sys::GvoxBlitContext,
2017        ) -> Self {
2018            Self { blit_ctx, ctx }
2019        }
2020    }
2021
2022    /// Describes the types associated with a given operation kind.
2023    pub trait AdapterKindAssociation: AdapterKind {
2024        /// The blitting context that is provided for adapters of this type.
2025        type BlitContext: BlitContextType;
2026    }
2027
2028    impl AdapterKindAssociation for Input {
2029        type BlitContext = InputBlitContext;
2030    }
2031
2032    impl AdapterKindAssociation for Output {
2033        type BlitContext = OutputBlitContext;
2034    }
2035
2036    impl AdapterKindAssociation for Parse {
2037        type BlitContext = ParseBlitContext;
2038    }
2039
2040    impl AdapterKindAssociation for Serialize {
2041        type BlitContext = SerializeBlitContext;
2042    }
2043
2044    /// Provides the ability to register an adapter of the given type with a context. Automatically
2045    /// implemented for all adapter types with context handlers.
2046    pub trait RegisterableAdapter<K: AdapterKind>: AdapterDescriptor<K> + NamedAdapter {
2047        /// Registers the given adapter with the underlying context, and returns a pointer to it if the operation
2048        /// was successful.
2049        ///
2050        /// # Safety
2051        ///
2052        /// The provided pointer must be a valid reference to a context.
2053        unsafe fn register_adapter(
2054            ptr: *mut gvox_sys::GvoxContext,
2055        ) -> Result<*mut gvox_sys::GvoxAdapter, GvoxError>;
2056    }
2057
2058    impl<T: AdapterDescriptor<Input> + NamedAdapter> RegisterableAdapter<Input> for T
2059    where
2060        T::Handler: InputAdapterHandler<T>,
2061    {
2062        unsafe fn register_adapter(
2063            ptr: *mut gvox_sys::GvoxContext,
2064        ) -> Result<*mut gvox_sys::GvoxAdapter, GvoxError> {
2065            let name =
2066                CString::new(Self::name()).expect("Failed to convert Rust string to C string");
2067            let adapter_info = gvox_sys::GvoxInputAdapterInfo {
2068                base_info: create_base_adapter_info::<Input, Self>(&name),
2069                read: Some(InputContextHolder::read::<Self>),
2070            };
2071            let adapter = gvox_sys::gvox_register_input_adapter(ptr, &adapter_info);
2072            ContextInner::get_error_from_raw_ptr(ptr).map(|()| adapter)
2073        }
2074    }
2075
2076    impl<T: AdapterDescriptor<Output> + NamedAdapter> RegisterableAdapter<Output> for T
2077    where
2078        T::Handler: OutputAdapterHandler<T>,
2079    {
2080        unsafe fn register_adapter(
2081            ptr: *mut gvox_sys::GvoxContext,
2082        ) -> Result<*mut gvox_sys::GvoxAdapter, GvoxError> {
2083            let name =
2084                CString::new(Self::name()).expect("Failed to convert Rust string to C string");
2085            let adapter_info = gvox_sys::GvoxOutputAdapterInfo {
2086                base_info: create_base_adapter_info::<Output, Self>(&name),
2087                write: Some(OutputContextHolder::write::<Self>),
2088                reserve: Some(OutputContextHolder::reserve::<Self>),
2089            };
2090            let adapter = gvox_sys::gvox_register_output_adapter(ptr, &adapter_info);
2091            ContextInner::get_error_from_raw_ptr(ptr).map(|()| adapter)
2092        }
2093    }
2094
2095    impl<T: AdapterDescriptor<Parse> + NamedAdapter> RegisterableAdapter<Parse> for T
2096    where
2097        T::Handler: ParseAdapterHandler<T>,
2098    {
2099        unsafe fn register_adapter(
2100            ptr: *mut gvox_sys::GvoxContext,
2101        ) -> Result<*mut gvox_sys::GvoxAdapter, GvoxError> {
2102            let name =
2103                CString::new(Self::name()).expect("Failed to convert Rust string to C string");
2104            let adapter_info = gvox_sys::GvoxParseAdapterInfo {
2105                base_info: create_base_adapter_info::<Parse, Self>(&name),
2106                query_details: Some(ParseContextHolder::query_details::<Self>),
2107                query_parsable_range: Some(ParseContextHolder::query_parsable_range::<Self>),
2108                query_region_flags: Some(ParseContextHolder::query_region_flags::<Self>),
2109                load_region: Some(ParseContextHolder::load_region::<Self>),
2110                unload_region: Some(ParseContextHolder::unload_region::<Self>),
2111                sample_region: Some(ParseContextHolder::sample_region::<Self>),
2112                parse_region: Some(ParseContextHolder::parse_region::<Self>),
2113            };
2114            let adapter = gvox_sys::gvox_register_parse_adapter(ptr, &adapter_info);
2115            ContextInner::get_error_from_raw_ptr(ptr).map(|()| adapter)
2116        }
2117    }
2118
2119    impl<T: AdapterDescriptor<Serialize> + NamedAdapter> RegisterableAdapter<Serialize> for T
2120    where
2121        T::Handler: SerializeAdapterHandler<T>,
2122    {
2123        unsafe fn register_adapter(
2124            ptr: *mut gvox_sys::GvoxContext,
2125        ) -> Result<*mut gvox_sys::GvoxAdapter, GvoxError> {
2126            let name =
2127                CString::new(Self::name()).expect("Failed to convert Rust string to C string");
2128            let adapter_info = gvox_sys::GvoxSerializeAdapterInfo {
2129                base_info: create_base_adapter_info::<Serialize, Self>(&name),
2130                serialize_region: Some(SerializeContextHolder::serialize_region::<Self>),
2131                receive_region: Some(SerializeContextHolder::receive_region::<Self>),
2132            };
2133            let adapter = gvox_sys::gvox_register_serialize_adapter(ptr, &adapter_info);
2134            ContextInner::get_error_from_raw_ptr(ptr).map(|()| adapter)
2135        }
2136    }
2137
2138    /// Creates the base adapter info for the adapter of the given name and type.
2139    fn create_base_adapter_info<K: AdapterKindAssociation, A: AdapterDescriptor<K>>(
2140        name: &CStr,
2141    ) -> gvox_sys::GvoxAdapterBaseInfo
2142    where
2143        A::Handler: BaseAdapterHandler<K, A>,
2144    {
2145        gvox_sys::GvoxAdapterBaseInfo {
2146            name_str: name.as_ptr(),
2147            create: Some(AdapterContextHolder::create::<K, A>),
2148            destroy: Some(AdapterContextHolder::destroy::<K, A>),
2149            blit_begin: Some(AdapterContextHolder::blit_begin::<K, A>),
2150            blit_end: Some(AdapterContextHolder::blit_end::<K, A>),
2151        }
2152    }
2153}