1pub const PIXELFLOW_ABI_VERSION: u32 = 1;
5
6pub const PIXELFLOW_PLUGIN_ENTRY_SYMBOL: &[u8] = b"pixelflow_plugin_entry_v1\0";
8
9#[repr(C)]
11#[derive(Clone, Copy, Debug, Eq, PartialEq)]
12pub struct PixelflowStringView {
13 pub ptr: *const u8,
15 pub len: usize,
17}
18
19impl PixelflowStringView {
20 #[must_use]
22 pub const fn from_rust_str(value: &str) -> Self {
23 Self {
24 ptr: value.as_ptr(),
25 len: value.len(),
26 }
27 }
28}
29
30#[repr(C)]
32#[derive(Clone, Copy, Debug, Eq, PartialEq)]
33pub enum PixelflowErrorCategory {
34 None = 0,
36 Plugin = 1,
38 Internal = 2,
40}
41
42#[repr(C)]
44#[derive(Clone, Copy, Debug, Eq, PartialEq)]
45pub enum PixelflowMetadataKind {
46 Bool = 1,
48 Int = 2,
50 Float = 3,
52 String = 4,
54 Array = 5,
56 Rational = 6,
58 Blob = 7,
60}
61
62#[repr(C)]
64#[derive(Clone, Copy, Debug, Eq, PartialEq)]
65pub struct PixelflowStatus {
66 pub size: u32,
68 pub version: u32,
70 pub status_code: i32,
72 pub category: PixelflowErrorCategory,
74 pub error_code: PixelflowStringView,
76 pub message: PixelflowStringView,
78 pub reserved: [usize; 4],
80}
81
82impl PixelflowStatus {
83 #[must_use]
85 pub const fn ok() -> Self {
86 Self {
87 size: std::mem::size_of::<Self>() as u32,
88 version: PIXELFLOW_ABI_VERSION,
89 status_code: 0,
90 category: PixelflowErrorCategory::None,
91 error_code: PixelflowStringView::from_rust_str(""),
92 message: PixelflowStringView::from_rust_str(""),
93 reserved: [0; 4],
94 }
95 }
96
97 #[must_use]
99 pub const fn plugin_error(code: &'static str, message: &'static str) -> Self {
100 Self {
101 status_code: 1,
102 category: PixelflowErrorCategory::Plugin,
103 error_code: PixelflowStringView::from_rust_str(code),
104 message: PixelflowStringView::from_rust_str(message),
105 ..Self::ok()
106 }
107 }
108
109 #[must_use]
111 pub const fn is_ok(self) -> bool {
112 self.status_code == 0
113 }
114}
115
116#[repr(C)]
118pub struct PixelflowRegistrar {
119 _private: [u8; 0],
120}
121
122#[repr(C)]
124#[derive(Clone, Copy, Debug)]
125pub struct PixelflowFilterDescriptorV1 {
126 pub size: u32,
128 pub version: u32,
130 pub name: PixelflowStringView,
132 pub publisher: PixelflowStringView,
134 pub plugin: PixelflowStringView,
136 pub reserved: [usize; 4],
138}
139
140#[repr(C)]
142#[derive(Clone, Copy)]
143pub struct PixelflowHostApiV1 {
144 pub size: u32,
146 pub version: u32,
148 pub register_filter: unsafe extern "C" fn(
150 *mut PixelflowRegistrar,
151 *const PixelflowFilterDescriptorV1,
152 ) -> PixelflowStatus,
153 pub register_metadata_key: unsafe extern "C" fn(
155 *mut PixelflowRegistrar,
156 PixelflowStringView,
157 PixelflowMetadataKind,
158 ) -> PixelflowStatus,
159 pub log: unsafe extern "C" fn(*mut PixelflowRegistrar, u32, PixelflowStringView),
161 pub reserved: [usize; 4],
163}
164
165#[repr(C)]
167#[derive(Clone, Copy)]
168pub struct PixelflowPluginApiV1 {
169 pub size: u32,
171 pub version: u32,
173 pub plugin_name: unsafe extern "C" fn() -> PixelflowStringView,
175 pub register:
177 unsafe extern "C" fn(*const PixelflowHostApiV1, *mut PixelflowRegistrar) -> PixelflowStatus,
178 pub reserved: [usize; 5],
180}
181
182pub type PixelflowPluginEntryV1 =
184 unsafe extern "C" fn(*const PixelflowHostApiV1, *mut PixelflowPluginApiV1) -> PixelflowStatus;
185
186#[cfg(test)]
187mod tests {
188 use std::mem::{align_of, size_of};
189
190 use super::{PIXELFLOW_ABI_VERSION, PixelflowPluginApiV1, PixelflowStatus};
191
192 #[test]
193 fn abi_version_is_one() {
194 assert_eq!(PIXELFLOW_ABI_VERSION, 1);
195 }
196
197 #[test]
198 fn status_success_has_zero_code() {
199 assert_eq!(PixelflowStatus::ok().status_code, 0);
200 }
201
202 #[test]
203 fn plugin_api_layout_has_stable_size_and_alignment() {
204 assert_eq!(size_of::<PixelflowPluginApiV1>(), 64);
205 assert_eq!(align_of::<PixelflowPluginApiV1>(), 8);
206 }
207}