Skip to main content

whiteout/
lib.rs

1// SPDX-License-Identifier: BSD-3-Clause
2// Copyright (c) 2026 Fernando Sahmkow
3
4// The README is the crate overview, and it comes first: doc attributes and
5// `//!` comments concatenate in source order, so this must precede the
6// block below or the landing page opens on implementation detail.
7#![doc = include_str!("../README.md")]
8
9//! # Layout contract
10//!
11//! Value types such as [`math::Vector3f`] are `#[repr(C)]` mirrors of their
12//! C++ counterparts and cross the FFI boundary with no conversion. Their
13//! sizes are pinned by `const` assertions at compile time, and
14//! [`math::check_abi`] re-verifies them against the library actually linked:
15//!
16//! ```no_run
17//! whiteout::math::check_abi().expect("native library layout mismatch");
18//! ```
19//!
20//! # Errors
21//!
22//! The underlying C++ library does not throw, and signals absence with
23//! `std::optional`. This binding follows that: operations that can simply
24//! find nothing return [`Option`], and [`Result`] is reserved for the few
25//! calls that produce a real diagnostic.
26//!
27//! # Zero-copy pixel access
28//!
29//! [`textures::Texture::data`] and `data_mut` borrow the C++ buffer
30//! directly — nothing is copied in either direction. That is safe because
31//! the slice borrows the texture, so the compiler rejects any use that
32//! could dangle. This must not compile:
33//!
34//! ```compile_fail
35//! use whiteout::textures::{PixelFormat, Texture};
36//! let mut tex = Texture::create_2d(PixelFormat::RGBA8, 4, 4, 1).unwrap();
37//! let pixels = tex.data_mut();
38//! drop(tex);            // owner released while `pixels` is still alive
39//! pixels[0] = 1;
40//! ```
41//!
42//! Neither may a shared and a mutable view coexist:
43//!
44//! ```compile_fail
45//! use whiteout::textures::{PixelFormat, Texture};
46//! let mut tex = Texture::create_2d(PixelFormat::RGBA8, 4, 4, 1).unwrap();
47//! let shared = tex.data();
48//! let unique = tex.data_mut();   // second borrow, one of them mutable
49//! let _ = (shared[0], unique[0]);
50//! ```
51//!
52//! C# and C++ can only document these hazards; here they are compile
53//! errors, which is what makes handing out the raw buffer reasonable.
54
55#![deny(unsafe_op_in_unsafe_fn)]
56#![warn(missing_debug_implementations)]
57
58#[cfg(feature = "casc")]
59pub mod casc;
60#[cfg(feature = "casc")]
61pub mod casc_ext;
62pub mod host;
63pub mod interfaces;
64pub mod m2;
65pub mod m3;
66pub mod math;
67pub mod mdx;
68#[cfg(feature = "mpq")]
69pub mod mpq;
70mod support;
71pub mod textures;
72
73pub use support::{BorrowedSlice, Bytes, Ref, RefMut};
74
75use core::fmt;
76
77/// Errors that can cross the binding boundary.
78///
79/// Deliberately small: the C++ library reports "not found" through
80/// `std::optional`, which this binding surfaces as [`Option`] rather than
81/// as an error.
82#[non_exhaustive]
83#[derive(Debug, Clone, PartialEq, Eq)]
84pub enum Error {
85    /// A `std::string*` diagnostic from the native side.
86    Native(String),
87    /// The linked library's layout disagrees with what this crate was
88    /// generated against — see [`math::check_abi`].
89    Layout {
90        what: &'static str,
91        expected: usize,
92        actual: usize,
93    },
94    /// A cargo feature is enabled but the linked library was built without
95    /// the matching `WHITEOUT_ENABLE_*`.
96    FeatureDisabled(&'static str),
97    /// The native library produced an enum discriminant this crate does not
98    /// know. Indicates version skew rather than bad input.
99    UnknownEnum { name: &'static str, value: i32 },
100}
101
102impl fmt::Display for Error {
103    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
104        match self {
105            Error::Native(msg) => write!(f, "{msg}"),
106            Error::Layout {
107                what,
108                expected,
109                actual,
110            } => write!(
111                f,
112                "native layout mismatch for {what}: this crate expects {expected}, \
113                 the linked library reports {actual}"
114            ),
115            Error::FeatureDisabled(feat) => write!(
116                f,
117                "the `{feat}` feature is enabled but the linked whiteout_native \
118                 was built without it"
119            ),
120            Error::UnknownEnum { name, value } => write!(
121                f,
122                "the native library returned {value} for {name}, which this \
123                 crate does not know — the linked library is newer"
124            ),
125        }
126    }
127}
128
129impl std::error::Error for Error {}