1use enum_dispatch::enum_dispatch;
3use nsi_sys::*;
4use std::{
5 ffi::{c_void, CString},
6 marker::PhantomData,
7 pin::Pin,
8};
9use ustr::Ustr;
10
11#[allow(unused_imports)]
13use crate::*;
14
15#[inline(always)]
16pub(crate) fn get_c_param_vec(
17 args: Option<&ArgSlice>,
18) -> (i32, *const NSIParam, Vec<NSIParam>) {
19 let args = match args {
20 Some(args) => args
21 .iter()
22 .map(|arg| NSIParam {
23 name: arg.name.as_char_ptr(),
24 data: arg.data.as_c_ptr(),
25 type_: arg.data.type_() as _,
26 arraylength: arg.array_length as _,
27 count: (arg.data.len() / arg.array_length) as _,
28 flags: arg.flags as _,
29 })
30 .collect::<Vec<_>>(),
31 None => Vec::new(),
32 };
33
34 (args.len() as _, args.as_ptr(), args)
35}
36
37pub type ArgSlice<'a, 'b> = [Arg<'a, 'b>];
40
41pub type ArgVec<'a, 'b> = Vec<Arg<'a, 'b>>;
44
45#[derive(Debug, Clone)]
48pub struct Arg<'a, 'b> {
49 pub(crate) name: Ustr,
50 pub(crate) data: ArgData<'a, 'b>,
51 pub(crate) array_length: usize,
53 pub(crate) flags: i32,
55}
56
57impl<'a, 'b> Arg<'a, 'b> {
58 #[inline]
59 pub fn new(name: &str, data: ArgData<'a, 'b>) -> Self {
60 Arg {
61 name: Ustr::from(name),
62 data,
63 array_length: 1,
64 flags: 0,
65 }
66 }
67
68 #[inline]
70 pub fn array_len(mut self, length: usize) -> Self {
71 self.array_length = length;
72 self.flags |= NSIParamFlags::IsArray.bits();
73 self
74 }
75
76 #[inline]
78 pub fn per_face(mut self) -> Self {
79 self.flags |= NSIParamFlags::PerFace.bits();
80 self
81 }
82
83 #[inline]
85 pub fn per_vertex(mut self) -> Self {
86 self.flags |= NSIParamFlags::PerVertex.bits();
87 self
88 }
89
90 #[inline]
92 pub fn linear_interpolation(mut self) -> Self {
93 self.flags |= NSIParamFlags::InterpolateLinear.bits();
94 self
95 }
96}
97
98#[enum_dispatch(ArgData)]
99pub(crate) trait ArgDataMethods {
100 fn type_(&self) -> Type;
102 fn len(&self) -> usize;
103 fn as_c_ptr(&self) -> *const c_void;
104}
105
106#[enum_dispatch]
117#[derive(Debug, Clone)]
118pub enum ArgData<'a, 'b> {
119 Float,
121 Floats(Floats<'a>),
123 Double,
125 Doubles(Doubles<'a>),
127 Integer,
129 Integers(Integers<'a>),
131 String(String),
133 Strings(Strings),
135 Color(Color<'a>),
138 Colors(Colors<'a>),
140 Point(Point<'a>),
142 Points(Points<'a>),
144 Vector(Vector<'a>),
146 Vectors(Vectors<'a>),
148 Normal(Normal<'a>),
150 Normals(Normals<'a>),
152 Matrix(Matrix<'a>),
154 Matrices(Matrices<'a>),
156 DoubleMatrix(DoubleMatrix<'a>),
158 DoubleMatrices(DoubleMatrices<'a>),
160 Reference(Reference<'b>),
197 References(References<'b>),
199 Callback(Callback<'b>),
201}
202
203macro_rules! nsi_data_def {
204 ($type: ty, $name: ident, $nsi_type: expr) => {
205 #[derive(Debug, Clone)]
207 pub struct $name {
208 data: $type,
209 }
210
211 impl $name {
212 pub fn new(data: $type) -> Self {
213 Self { data }
214 }
215 }
216
217 impl ArgDataMethods for $name {
218 fn type_(&self) -> Type {
219 $nsi_type
220 }
221
222 fn len(&self) -> usize {
223 1
224 }
225
226 fn as_c_ptr(&self) -> *const c_void {
227 &self.data as *const $type as _
228 }
229 }
230 };
231}
232
233macro_rules! nsi_data_array_def {
234 ($type: ty, $name: ident, $nsi_type: expr) => {
235 #[derive(Debug, Clone)]
237 pub struct $name<'a> {
238 data: &'a [$type],
239 }
240
241 impl<'a> $name<'a> {
242 pub fn new(data: &'a [$type]) -> Self {
243 debug_assert_eq!(0, data.len() % $nsi_type.elemensize());
244 Self { data }
245 }
246 }
247
248 impl<'a> ArgDataMethods for $name<'a> {
249 fn type_(&self) -> Type {
250 $nsi_type
251 }
252
253 fn len(&self) -> usize {
254 self.data.len() / $nsi_type.elemensize()
255 }
256
257 fn as_c_ptr(&self) -> *const c_void {
258 self.data.as_ptr() as _
259 }
260 }
261 };
262}
263
264macro_rules! nsi_tuple_data_def {
265 ($type: tt, $len: expr, $name: ident, $nsi_type: expr) => {
266 #[derive(Debug, Clone)]
268 pub struct $name<'a> {
269 data: &'a [$type; $len],
270 }
271
272 impl<'a> $name<'a> {
273 pub fn new(data: &'a [$type; $len]) -> Self {
274 Self { data }
275 }
276 }
277
278 impl<'a> ArgDataMethods for $name<'a> {
279 fn type_(&self) -> Type {
280 $nsi_type
281 }
282
283 fn len(&self) -> usize {
284 1
285 }
286
287 fn as_c_ptr(&self) -> *const c_void {
288 self.data.as_ptr() as _
289 }
290 }
291 };
292}
293
294nsi_data_def!(f32, Float, Type::Float);
295nsi_data_def!(f64, Double, Type::Double);
296nsi_data_def!(i32, Integer, Type::Integer);
297
298#[derive(Debug, Clone)]
300pub struct Reference<'a> {
301 data: *const c_void,
302 _marker: PhantomData<&'a ()>,
303}
304
305unsafe impl Send for Reference<'static> {}
306unsafe impl Sync for Reference<'static> {}
307
308impl<'a> Reference<'a> {
309 pub fn new<T: Sized>(data: Pin<&'a T>) -> Self {
310 Self {
311 data: data.get_ref() as *const _ as _,
312 _marker: PhantomData,
313 }
314 }
315}
316
317impl<'a> ArgDataMethods for Reference<'a> {
318 fn type_(&self) -> Type {
319 Type::Reference
320 }
321
322 fn len(&self) -> usize {
323 1
324 }
325
326 fn as_c_ptr(&self) -> *const c_void {
327 self.data
328 }
329}
330
331pub trait CallbackPtr {
332 #[doc(hidden)]
333 #[allow(clippy::wrong_self_convention)]
334 fn to_ptr(self) -> *const c_void;
335}
336
337unsafe impl Send for Callback<'static> {}
338unsafe impl Sync for Callback<'static> {}
339
340#[derive(Debug, Clone)]
342pub struct Callback<'a> {
343 data: *const c_void,
344 _marker: PhantomData<&'a mut ()>,
345}
346
347impl<'a> Callback<'a> {
348 pub fn new<T: CallbackPtr>(data: T) -> Self {
349 Self {
350 data: data.to_ptr(),
351 _marker: PhantomData,
352 }
353 }
354}
355
356impl<'a> ArgDataMethods for Callback<'a> {
357 fn type_(&self) -> Type {
358 Type::Reference
359 }
360
361 fn len(&self) -> usize {
362 1
363 }
364
365 fn as_c_ptr(&self) -> *const c_void {
366 self.data
367 }
368}
369
370#[derive(Debug, Clone)]
372pub struct String {
373 #[allow(dead_code)]
374 data: CString,
375 pointer: *const c_void,
377}
378
379unsafe impl Send for String {}
380unsafe impl Sync for String {}
381
382impl String {
383 pub fn new<T: Into<Vec<u8>>>(data: T) -> Self {
384 let data = CString::new(data).unwrap();
385 let pointer = data.as_ptr() as _;
386
387 String { data, pointer }
388 }
389}
390
391impl ArgDataMethods for String {
392 fn type_(&self) -> Type {
393 Type::String
394 }
395
396 fn len(&self) -> usize {
397 1
398 }
399
400 fn as_c_ptr(&self) -> *const c_void {
401 &self.pointer as *const *const c_void as _
402 }
403}
404
405nsi_data_array_def!(f32, Floats, Type::Float);
406nsi_data_array_def!(f64, Doubles, Type::Double);
407nsi_data_array_def!(i32, Integers, Type::Integer);
408nsi_data_array_def!(f32, Colors, Type::Color);
409nsi_data_array_def!(f32, Points, Type::Point);
410nsi_data_array_def!(f32, Vectors, Type::Vector);
411nsi_data_array_def!(f32, Normals, Type::Normal);
412nsi_data_array_def!(f32, Matrices, Type::Matrix);
413nsi_data_array_def!(f64, DoubleMatrices, Type::DoubleMatrix);
414
415#[derive(Debug, Clone)]
417pub struct References<'a> {
418 data: Vec<*const c_void>,
419 _marker: PhantomData<&'a ()>,
420}
421
422unsafe impl Send for References<'static> {}
423unsafe impl Sync for References<'static> {}
424
425impl<'a> References<'a> {
426 pub fn new<T>(data: &'a [&'a T]) -> Self {
427 debug_assert_eq!(0, data.len() % Type::Reference.elemensize());
428
429 Self {
430 data: data.iter().map(|r| r as *const _ as _).collect(),
431 _marker: PhantomData,
432 }
433 }
434}
435
436impl<'a> ArgDataMethods for References<'a> {
437 fn type_(&self) -> Type {
438 Type::Reference
439 }
440
441 fn len(&self) -> usize {
442 self.data.len() / Type::Reference.elemensize()
443 }
444
445 fn as_c_ptr(&self) -> *const c_void {
446 self.data.as_ptr() as _
447 }
448}
449
450#[derive(Debug, Clone)]
452pub struct Strings {
453 #[allow(dead_code)]
454 data: Vec<CString>,
455 pointer: Vec<*const c_void>,
456}
457
458unsafe impl Send for Strings {}
459unsafe impl Sync for Strings {}
460
461impl Strings {
462 pub fn new<T: Into<Vec<u8>> + Copy>(data: &[T]) -> Self {
463 let data = data
464 .iter()
465 .map(|s| CString::new(*s).unwrap())
466 .collect::<Vec<_>>();
467 let pointer = data.iter().map(|s| s.as_ptr() as _).collect();
468
469 Strings { data, pointer }
470 }
471}
472
473impl ArgDataMethods for Strings {
474 fn type_(&self) -> Type {
475 Type::String
476 }
477
478 fn len(&self) -> usize {
479 self.pointer.len()
480 }
481
482 fn as_c_ptr(&self) -> *const c_void {
483 self.pointer.as_ptr() as _
484 }
485}
486
487nsi_tuple_data_def!(f32, 3, Color, Type::Color);
488nsi_tuple_data_def!(f32, 3, Point, Type::Point);
489nsi_tuple_data_def!(f32, 3, Vector, Type::Vector);
490nsi_tuple_data_def!(f32, 3, Normal, Type::Normal);
491nsi_tuple_data_def!(f32, 16, Matrix, Type::Matrix);
492nsi_tuple_data_def!(f64, 16, DoubleMatrix, Type::DoubleMatrix);
493
494#[derive(Copy, Clone, Debug, PartialEq)]
496#[repr(i32)]
497pub(crate) enum Type {
498 Float = NSIType::Float as _,
500 Double = NSIType::Double as _,
502 Integer = NSIType::Integer as _,
504 String = NSIType::String as _,
506 Color = NSIType::Color as _,
510 Point = NSIType::Point as _,
512 Vector = NSIType::Vector as _,
514 Normal = NSIType::Normal as _,
516 Matrix = NSIType::Matrix as _,
518 DoubleMatrix = NSIType::DoubleMatrix as _,
520 Reference = NSIType::Pointer as _,
522}
523
524impl Type {
525 #[inline]
527 pub(crate) fn elemensize(&self) -> usize {
528 match self {
529 Type::Float => 1,
530 Type::Double => 1,
531 Type::Integer => 1,
532 Type::String => 1,
533 Type::Color => 3,
534 Type::Point => 3,
535 Type::Vector => 3,
536 Type::Normal => 3,
537 Type::Matrix => 16,
538 Type::DoubleMatrix => 16,
539 Type::Reference => 1,
540 }
541 }
542}
543
544#[macro_export]
546macro_rules! float {
547 ($name: tt, $value: expr) => {
548 nsi::Arg::new($name, nsi::ArgData::from(nsi::Float::new($value)))
549 };
550}
551
552#[macro_export]
554macro_rules! floats {
555 ($name: tt, $value: expr) => {
556 nsi::Arg::new($name, nsi::ArgData::from(nsi::Floats::new($value)))
557 };
558}
559
560#[macro_export]
562macro_rules! double {
563 ($name: tt, $value: expr) => {
564 nsi::Arg::new($name, nsi::ArgData::from(nsi::Double::new($value)))
565 };
566}
567
568#[macro_export]
570macro_rules! doubles {
571 ($name: tt, $value: expr) => {
572 nsi::Arg::new($name, nsi::ArgData::from(nsi::Doubles::new($value)))
573 };
574}
575
576#[macro_export]
578macro_rules! integer {
579 ($name: tt, $value: expr) => {
580 nsi::Arg::new($name, nsi::ArgData::from(nsi::Integer::new($value)))
581 };
582}
583
584#[macro_export]
586macro_rules! integers {
587 ($name: tt, $value: expr) => {
588 nsi::Arg::new($name, nsi::ArgData::from(nsi::Integers::new($value)))
589 };
590}
591
592#[macro_export]
594macro_rules! color {
595 ($name: tt, $value: expr) => {
596 nsi::Arg::new($name, nsi::ArgData::from(nsi::Color::new($value)))
597 };
598}
599
600#[macro_export]
602macro_rules! colors {
603 ($name: tt, $value: expr) => {
604 nsi::Arg::new($name, nsi::ArgData::from(nsi::Colors::new($value)))
605 };
606}
607
608#[macro_export]
610macro_rules! point {
611 ($name: tt, $value: expr) => {
612 nsi::Arg::new($name, nsi::ArgData::from(nsi::Point::new($value)))
613 };
614}
615
616#[macro_export]
618macro_rules! points {
619 ($name: tt, $value: expr) => {
620 nsi::Arg::new($name, nsi::ArgData::from(nsi::Points::new($value)))
621 };
622}
623
624#[macro_export]
626macro_rules! vector {
627 ($name: tt, $value: expr) => {
628 nsi::Arg::new($name, nsi::ArgData::from(nsi::Vector::new($value)))
629 };
630}
631
632#[macro_export]
634macro_rules! vectors {
635 ($name: tt, $value: expr) => {
636 nsi::Arg::new($name, nsi::ArgData::from(nsi::Vectors::new($value)))
637 };
638}
639
640#[macro_export]
642macro_rules! normal {
643 ($name: tt, $value: expr) => {
644 nsi::Arg::new($name, nsi::ArgData::from(nsi::Normal::new($value)))
645 };
646}
647
648#[macro_export]
650macro_rules! normals {
651 ($name: tt, $value: expr) => {
652 nsi::Arg::new($name, nsi::ArgData::from(nsi::Normals::new($value)))
653 };
654}
655
656#[macro_export]
659macro_rules! matrix {
660 ($name: tt, $value: expr) => {
661 nsi::Arg::new($name, nsi::ArgData::from(nsi::Matrix::new($value)))
662 };
663}
664
665#[macro_export]
668macro_rules! matrices {
669 ($name: tt, $value: expr) => {
670 nsi::Arg::new($name, nsi::ArgData::from(nsi::Matrices::new($value)))
671 };
672}
673
674#[macro_export]
696macro_rules! double_matrix {
697 ($name: tt, $value: expr) => {
698 nsi::Arg::new($name, nsi::ArgData::from(nsi::DoubleMatrix::new($value)))
699 };
700}
701
702#[macro_export]
705macro_rules! double_matrices {
706 ($name: tt, $value: expr) => {
707 nsi::Arg::new(
708 $name,
709 nsi::ArgData::from(nsi::DoubleMatrices::new($value)),
710 )
711 };
712}
713
714#[macro_export]
726macro_rules! string {
727 ($name: tt, $value: expr) => {
728 nsi::Arg::new($name, nsi::ArgData::from(nsi::String::new($value)))
729 };
730}
731
732#[macro_export]
749macro_rules! strings {
750 ($name: tt, $value: expr) => {
751 nsi::Arg::new($name, nsi::ArgData::from(nsi::Strings::new($value)))
752 };
753}
754
755#[macro_export]
757macro_rules! reference {
758 ($name: tt, $value: expr) => {
759 nsi::Arg::new($name, nsi::ArgData::from(nsi::Reference::new($value)))
760 };
761}
762
763#[macro_export]
765macro_rules! references {
766 ($name: tt, $value: expr) => {
767 nsi::Arg::new($name, nsi::ArgData::from(nsi::References::new($value)))
768 };
769}
770
771#[macro_export]
773macro_rules! callback {
774 ($name: tt, $value: expr) => {
775 nsi::Arg::new($name, nsi::ArgData::from(nsi::Callback::new($value)))
776 };
777}