1use enum_dispatch::enum_dispatch;
3use nsi_sys::*;
4use std::{
5 ffi::{CString, c_void},
6 marker::PhantomData,
7 num::NonZeroUsize,
8 pin::Pin,
9};
10use ustr::{Ustr, ustr};
11
12#[allow(unused_imports)]
14use crate::*;
15
16#[inline(always)]
17pub(crate) fn to_c_param_vec(
18 args: Option<&ArgSlice>,
19) -> (i32, *const NSIParam, Vec<NSIParam>) {
20 let args = match args {
21 Some(args) => args
22 .iter()
23 .map(|arg| NSIParam {
24 name: arg.name.as_char_ptr(),
25 data: arg.data.as_c_ptr(),
26 type_: arg.data.type_() as _,
27 arraylength: arg.array_length.get() as _,
28 count: (arg.data.len() / arg.array_length) as _,
29 flags: arg.flags as _,
30 })
31 .collect::<Vec<_>>(),
32 None => Vec::new(),
33 };
34
35 (args.len() as _, args.as_ptr(), args)
36}
37
38pub type ArgSlice<'a, 'b> = [Arg<'a, 'b>];
41
42pub type ArgVec<'a, 'b> = Vec<Arg<'a, 'b>>;
45
46#[derive(Debug, Clone)]
49pub struct Arg<'a, 'b> {
50 pub(crate) name: Ustr,
51 pub(crate) data: ArgData<'a, 'b>,
52 pub(crate) array_length: NonZeroUsize,
54 pub(crate) flags: i32,
56}
57
58impl<'a, 'b> Arg<'a, 'b> {
59 #[inline]
60 pub fn new(name: &str, data: ArgData<'a, 'b>) -> Self {
61 Arg {
62 name: ustr(name),
63 data,
64 array_length: NonZeroUsize::MIN,
65 flags: 0,
66 }
67 }
68
69 #[inline]
75 pub fn array_len(mut self, length: NonZeroUsize) -> Self {
76 self.array_length = length;
77 self.flags |= NSIParamFlags::IsArray.bits();
78 self
79 }
80
81 #[inline]
83 pub fn per_face(mut self) -> Self {
84 self.flags |= NSIParamFlags::PerFace.bits();
85 self
86 }
87
88 #[inline]
90 pub fn per_vertex(mut self) -> Self {
91 self.flags |= NSIParamFlags::PerVertex.bits();
92 self
93 }
94
95 #[inline]
97 pub fn linear_interpolation(mut self) -> Self {
98 self.flags |= NSIParamFlags::InterpolateLinear.bits();
99 self
100 }
101}
102
103#[enum_dispatch(ArgData)]
104pub(crate) trait ArgDataMethods {
105 fn type_(&self) -> DataType;
107 fn len(&self) -> usize;
108 fn as_c_ptr(&self) -> *const c_void;
109}
110
111#[enum_dispatch]
122#[derive(Debug, Clone)]
123pub enum ArgData<'a, 'b> {
124 F32,
126 F32Slice(F32Slice<'a>),
128 F64,
130 F64Slice(F64Slice<'a>),
132 I32,
134 I32Slice(I32Slice<'a>),
136 I64,
138 I64Slice(I64Slice<'a>),
140 String(String),
142 StringSlice(StringSlice),
144 Color(Color<'a>),
147 ColorSlice(ColorSlice<'a>),
149 Point(Point<'a>),
151 PointSlice(PointSlice<'a>),
153 Vector(Vector<'a>),
155 VectorSlice(VectorSlice<'a>),
157 Normal(Normal<'a>),
159 NormalSlice(NormalSlice<'a>),
161 MatrixF32(MatrixF32<'a>),
163 MatrixF32Slice(MatrixF32Slice<'a>),
165 MatrixF64(MatrixF64<'a>),
167 MatrixF64Slice(MatrixF64Slice<'a>),
169 Point4F32Slice(Point4F32Slice<'a>),
176 Reference(Reference<'b>),
214 ReferenceSlice(ReferenceSlice<'b>),
216 Callback(Callback<'b>),
218}
219
220macro_rules! nsi_data_def {
221 ($type: ty, $name: ident, $nsi_type: expr) => {
222 #[derive(Debug, Clone, PartialEq)]
224 pub struct $name {
225 data: $type,
226 }
227
228 impl $name {
229 pub fn new(data: $type) -> Self {
230 Self { data }
231 }
232 }
233
234 impl ArgDataMethods for $name {
235 fn type_(&self) -> DataType {
236 $nsi_type
237 }
238
239 fn len(&self) -> usize {
240 1
241 }
242
243 fn as_c_ptr(&self) -> *const c_void {
244 &self.data as *const $type as _
245 }
246 }
247 };
248}
249
250macro_rules! nsi_data_array_def {
251 ($type: ty, $name: ident, $nsi_type: expr) => {
252 #[derive(Debug, Clone, PartialEq)]
254 pub struct $name<'a> {
255 data: &'a [$type],
256 }
257
258 impl<'a> $name<'a> {
259 pub fn new(data: &'a [$type]) -> Self {
260 Self { data }
262 }
263 }
264
265 impl<'a> ArgDataMethods for $name<'a> {
266 fn type_(&self) -> DataType {
267 $nsi_type
268 }
269
270 fn len(&self) -> usize {
271 self.data.len() }
273
274 fn as_c_ptr(&self) -> *const c_void {
275 self.data.as_ptr() as _
276 }
277 }
278 };
279}
280
281macro_rules! nsi_tuple_data_array_def {
282 ($type: ty, $name: ident, $nsi_type: expr, $len: expr ) => {
283 #[derive(Debug, Clone, PartialEq)]
285 pub struct $name<'a> {
286 data: &'a [[$type; $len]],
287 }
288
289 impl<'a> $name<'a> {
290 pub fn new(data: &'a [[$type; $len]]) -> Self {
291 Self { data }
293 }
294 }
295
296 impl<'a> ArgDataMethods for $name<'a> {
297 fn type_(&self) -> DataType {
298 $nsi_type
299 }
300
301 fn len(&self) -> usize {
302 self.data.len() }
304
305 fn as_c_ptr(&self) -> *const c_void {
306 self.data.as_ptr() as _
307 }
308 }
309 };
310}
311
312macro_rules! nsi_tuple_data_def {
313 ($type: tt, $len: expr, $name: ident, $nsi_type: expr) => {
314 #[derive(Debug, Clone, PartialEq)]
316 pub struct $name<'a> {
317 data: &'a [$type; $len],
318 }
319
320 impl<'a> $name<'a> {
321 pub fn new(data: &'a [$type; $len]) -> Self {
322 Self { data }
323 }
324 }
325
326 impl<'a> ArgDataMethods for $name<'a> {
327 fn type_(&self) -> DataType {
328 $nsi_type
329 }
330
331 fn len(&self) -> usize {
332 1
333 }
334
335 fn as_c_ptr(&self) -> *const c_void {
336 self.data.as_ptr() as _
337 }
338 }
339 };
340}
341
342nsi_data_def!(f32, F32, DataType::F32);
343nsi_data_def!(f64, F64, DataType::F64);
344nsi_data_def!(i32, I32, DataType::I32);
345nsi_data_def!(i64, I64, DataType::I64);
346
347#[derive(Debug, Clone)]
357pub struct Reference<'a> {
358 data: *const c_void,
359 _marker: PhantomData<&'a ()>,
360}
361
362unsafe impl Send for Reference<'static> {}
365unsafe impl Sync for Reference<'static> {}
366
367pub trait StableDeref<'a> {
370 fn stable_deref(&self) -> *const c_void;
372}
373
374impl<'a, T: ?Sized> StableDeref<'a> for &'a Box<T> {
375 fn stable_deref(&self) -> *const c_void {
376 self.as_ref() as *const T as *const c_void
377 }
378}
379
380impl<'a, T: ?Sized> StableDeref<'a> for &'a Arc<T> {
381 fn stable_deref(&self) -> *const c_void {
382 self.as_ref() as *const T as *const c_void
383 }
384}
385
386impl<'a, T: ?Sized> StableDeref<'a> for &'a Pin<Box<T>> {
387 fn stable_deref(&self) -> *const c_void {
388 self.as_ref().get_ref() as *const T as *const c_void
389 }
390}
391
392use std::sync::Arc;
393
394impl<'a> Reference<'a> {
395 pub fn new<S: StableDeref<'a>>(data: S) -> Self {
398 let ptr = data.stable_deref();
399 debug_assert!(!ptr.is_null(), "Reference created with null pointer");
400
401 Self {
402 data: ptr,
403 _marker: PhantomData,
404 }
405 }
406
407 #[allow(clippy::borrowed_box)]
411 pub fn from_box<T: ?Sized>(data: &'a Box<T>) -> Self {
412 let ptr = data.as_ref() as *const T as *const c_void;
413 debug_assert!(!ptr.is_null(), "Reference created with null pointer");
414
415 Self {
416 data: ptr,
417 _marker: PhantomData,
418 }
419 }
420
421 pub fn from_arc<T: ?Sized>(data: &'a Arc<T>) -> Self {
425 let ptr = data.as_ref() as *const T as *const c_void;
426 debug_assert!(!ptr.is_null(), "Reference created with null pointer");
427
428 Self {
429 data: ptr,
430 _marker: PhantomData,
431 }
432 }
433
434 pub fn from_pin_box<T: ?Sized>(data: &'a Pin<Box<T>>) -> Self {
438 let ptr = data.as_ref().get_ref() as *const T as *const c_void;
439 debug_assert!(!ptr.is_null(), "Reference created with null pointer");
440
441 Self {
442 data: ptr,
443 _marker: PhantomData,
444 }
445 }
446
447 pub unsafe fn from_stable<T: ?Sized>(data: &'a T) -> Self {
460 let ptr = data as *const T as *const c_void;
461 debug_assert!(!ptr.is_null(), "Reference created with null pointer");
462
463 Self {
464 data: ptr,
465 _marker: PhantomData,
466 }
467 }
468
469 pub unsafe fn from_ptr(ptr: *const c_void) -> Self {
477 debug_assert!(!ptr.is_null(), "Reference created with null pointer");
478 Self {
479 data: ptr,
480 _marker: PhantomData,
481 }
482 }
483}
484
485impl<'a> ArgDataMethods for Reference<'a> {
486 fn type_(&self) -> DataType {
487 DataType::Reference
488 }
489
490 fn len(&self) -> usize {
491 1
492 }
493
494 fn as_c_ptr(&self) -> *const c_void {
498 &self.data as *const *const c_void as _
499 }
500}
501
502pub trait CallbackPtr {
503 #[doc(hidden)]
504 #[allow(clippy::wrong_self_convention)]
505 fn to_ptr(self) -> *const c_void;
506
507 #[doc(hidden)]
516 unsafe fn drop_ptr(ptr: *const c_void);
517}
518
519unsafe impl Send for Callback<'static> {}
520unsafe impl Sync for Callback<'static> {}
521
522#[derive(Debug, Clone)]
524pub struct Callback<'a> {
525 pub(crate) data: *const c_void,
526 pub(crate) drop_fn: unsafe fn(*const c_void),
530 _marker: PhantomData<&'a mut ()>,
531}
532
533impl<'a> Callback<'a> {
534 pub fn new<T: CallbackPtr>(data: T) -> Self {
535 Self {
536 data: data.to_ptr(),
537 drop_fn: T::drop_ptr,
538 _marker: PhantomData,
539 }
540 }
541}
542
543impl<'a> ArgDataMethods for Callback<'a> {
544 fn type_(&self) -> DataType {
545 DataType::Reference
546 }
547
548 fn len(&self) -> usize {
549 1
550 }
551
552 fn as_c_ptr(&self) -> *const c_void {
555 &self.data as *const *const c_void as _
556 }
557}
558
559#[derive(Debug, Clone)]
561pub struct String {
562 #[allow(dead_code)]
563 data: CString,
564 pointer: *const c_void,
566}
567
568unsafe impl Send for String {}
569unsafe impl Sync for String {}
570
571impl String {
572 pub fn new<T: Into<Vec<u8>>>(data: T) -> Self {
573 let data = CString::new(data).unwrap();
574 let pointer = data.as_ptr() as _;
575
576 String { data, pointer }
577 }
578
579 pub fn as_str(&self) -> Option<&str> {
589 self.data.to_str().ok()
590 }
591}
592
593impl ArgDataMethods for String {
594 fn type_(&self) -> DataType {
595 DataType::String
596 }
597
598 fn len(&self) -> usize {
599 1
600 }
601
602 fn as_c_ptr(&self) -> *const c_void {
603 &self.pointer as *const *const c_void as _
604 }
605}
606
607nsi_data_array_def!(f32, F32Slice, DataType::F32);
608nsi_data_array_def!(f64, F64Slice, DataType::F64);
609nsi_data_array_def!(i32, I32Slice, DataType::I32);
610nsi_data_array_def!(i64, I64Slice, DataType::I64);
611nsi_tuple_data_array_def!(f32, ColorSlice, DataType::Color, 3);
612nsi_tuple_data_array_def!(f32, PointSlice, DataType::Point, 3);
613nsi_tuple_data_array_def!(f32, VectorSlice, DataType::Vector, 3);
614nsi_tuple_data_array_def!(f32, NormalSlice, DataType::Normal, 3);
615nsi_tuple_data_array_def!(f32, MatrixF32Slice, DataType::MatrixF32, 16);
616nsi_tuple_data_array_def!(f64, MatrixF64Slice, DataType::MatrixF64, 16);
617
618#[derive(Debug, Clone, PartialEq)]
627pub struct Point4F32Slice<'a> {
628 data: &'a [[f32; 4]],
629}
630
631impl<'a> Point4F32Slice<'a> {
632 pub fn new(data: &'a [[f32; 4]]) -> Self {
633 Self { data }
634 }
635}
636
637impl<'a> ArgDataMethods for Point4F32Slice<'a> {
638 fn type_(&self) -> DataType {
639 DataType::F32
640 }
641
642 fn len(&self) -> usize {
646 self.data.len() * 4
647 }
648
649 fn as_c_ptr(&self) -> *const c_void {
650 self.data.as_ptr() as _
651 }
652}
653
654#[derive(Debug, Clone)]
656pub struct ReferenceSlice<'a> {
657 data: Vec<*const c_void>,
658 _marker: PhantomData<&'a ()>,
659}
660
661unsafe impl Send for ReferenceSlice<'static> {}
662unsafe impl Sync for ReferenceSlice<'static> {}
663
664impl<'a> ReferenceSlice<'a> {
665 pub fn new<T>(data: &'a [&'a T]) -> Self {
666 debug_assert_eq!(0, data.len() % DataType::Reference.elemensize());
667
668 Self {
669 data: data.iter().map(|r| r as *const _ as _).collect(),
670 _marker: PhantomData,
671 }
672 }
673}
674
675impl<'a> ArgDataMethods for ReferenceSlice<'a> {
676 fn type_(&self) -> DataType {
677 DataType::Reference
678 }
679
680 fn len(&self) -> usize {
681 self.data.len() / DataType::Reference.elemensize()
682 }
683
684 fn as_c_ptr(&self) -> *const c_void {
685 self.data.as_ptr() as _
686 }
687}
688
689#[derive(Debug, Clone)]
691pub struct StringSlice {
692 #[allow(dead_code)]
693 data: Vec<CString>,
694 pointer: Vec<*const c_void>,
695}
696
697unsafe impl Send for StringSlice {}
698unsafe impl Sync for StringSlice {}
699
700impl StringSlice {
701 pub fn new<T: Into<Vec<u8>> + Copy>(data: &[T]) -> Self {
702 let data = data
703 .iter()
704 .map(|s| CString::new(*s).unwrap())
705 .collect::<Vec<_>>();
706 let pointer = data.iter().map(|s| s.as_ptr() as _).collect();
707
708 StringSlice { data, pointer }
709 }
710}
711
712impl ArgDataMethods for StringSlice {
713 fn type_(&self) -> DataType {
714 DataType::String
715 }
716
717 fn len(&self) -> usize {
718 self.pointer.len()
719 }
720
721 fn as_c_ptr(&self) -> *const c_void {
722 self.pointer.as_ptr() as _
723 }
724}
725
726nsi_tuple_data_def!(f32, 3, Color, DataType::Color);
727nsi_tuple_data_def!(f32, 3, Point, DataType::Point);
728nsi_tuple_data_def!(f32, 3, Vector, DataType::Vector);
729nsi_tuple_data_def!(f32, 3, Normal, DataType::Normal);
730nsi_tuple_data_def!(f32, 16, MatrixF32, DataType::MatrixF32);
731nsi_tuple_data_def!(f64, 16, MatrixF64, DataType::MatrixF64);
732
733#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
735#[repr(i32)]
736pub(crate) enum DataType {
737 F32 = NSIType::F32 as _,
739 F64 = NSIType::F64 as _,
741 I32 = NSIType::I32 as _,
743 I64 = NSIType::I64 as _,
745 String = NSIType::String as _,
747 Color = NSIType::Color as _,
751 Point = NSIType::Point as _,
753 Vector = NSIType::Vector as _,
755 Normal = NSIType::Normal as _,
757 MatrixF32 = NSIType::MatrixF32 as _,
759 MatrixF64 = NSIType::MatrixF64 as _,
761 Reference = NSIType::Pointer as _,
763}
764
765impl DataType {
766 #[inline]
768 pub(crate) fn elemensize(&self) -> usize {
769 match self {
770 DataType::F32 => 1,
771 DataType::F64 => 1,
772 DataType::I32 => 1,
773 DataType::I64 => 1,
774 DataType::String => 1,
775 DataType::Color => 3,
776 DataType::Point => 3,
777 DataType::Vector => 3,
778 DataType::Normal => 3,
779 DataType::MatrixF32 => 16,
780 DataType::MatrixF64 => 16,
781 DataType::Reference => 1,
782 }
783 }
784}
785
786#[macro_export]
792macro_rules! f32 {
793 ($name: literal, $value: expr) => {
794 nsi::Arg::new($name, nsi::ArgData::from(nsi::F32::new($value)))
795 };
796 ($name: path, $value: expr) => {{
797 const __ATTR_CHECK: $crate::Attribute<f32> = $name;
798 nsi::Arg::new(
799 __ATTR_CHECK.name(),
800 nsi::ArgData::from(nsi::F32::new($value)),
801 )
802 }};
803}
804
805#[macro_export]
810macro_rules! f32_slice {
811 ($name: literal, $value: expr) => {
812 nsi::Arg::new($name, nsi::ArgData::from(nsi::F32Slice::new($value)))
813 };
814 ($name: path, $value: expr) => {{
815 const __ATTR_CHECK: $crate::Attribute<[f32]> = $name;
816 nsi::Arg::new(
817 __ATTR_CHECK.name(),
818 nsi::ArgData::from(nsi::F32Slice::new($value)),
819 )
820 }};
821}
822
823#[macro_export]
828macro_rules! f64 {
829 ($name: literal, $value: expr) => {
830 nsi::Arg::new($name, nsi::ArgData::from(nsi::F64::new($value)))
831 };
832 ($name: path, $value: expr) => {{
833 const __ATTR_CHECK: $crate::Attribute<f64> = $name;
834 nsi::Arg::new(
835 __ATTR_CHECK.name(),
836 nsi::ArgData::from(nsi::F64::new($value)),
837 )
838 }};
839}
840
841#[macro_export]
846macro_rules! f64_slice {
847 ($name: literal, $value: expr) => {
848 nsi::Arg::new($name, nsi::ArgData::from(nsi::F64Slice::new($value)))
849 };
850 ($name: path, $value: expr) => {{
851 const __ATTR_CHECK: $crate::Attribute<[f64]> = $name;
852 nsi::Arg::new(
853 __ATTR_CHECK.name(),
854 nsi::ArgData::from(nsi::F64Slice::new($value)),
855 )
856 }};
857}
858
859#[macro_export]
864macro_rules! i32 {
865 ($name: literal, $value: expr) => {
866 nsi::Arg::new($name, nsi::ArgData::from(nsi::I32::new($value)))
867 };
868 ($name: path, $value: expr) => {{
869 const __ATTR_CHECK: $crate::Attribute<i32> = $name;
870 nsi::Arg::new(
871 __ATTR_CHECK.name(),
872 nsi::ArgData::from(nsi::I32::new($value)),
873 )
874 }};
875}
876
877#[macro_export]
882macro_rules! i32_slice {
883 ($name: literal, $value: expr) => {
884 nsi::Arg::new($name, nsi::ArgData::from(nsi::I32Slice::new($value)))
885 };
886 ($name: path, $value: expr) => {{
887 const __ATTR_CHECK: $crate::Attribute<[i32]> = $name;
888 nsi::Arg::new(
889 __ATTR_CHECK.name(),
890 nsi::ArgData::from(nsi::I32Slice::new($value)),
891 )
892 }};
893}
894
895#[macro_export]
900macro_rules! i64 {
901 ($name: literal, $value: expr) => {
902 nsi::Arg::new($name, nsi::ArgData::from(nsi::I64::new($value)))
903 };
904 ($name: path, $value: expr) => {{
905 const __ATTR_CHECK: $crate::Attribute<i64> = $name;
906 nsi::Arg::new(
907 __ATTR_CHECK.name(),
908 nsi::ArgData::from(nsi::I64::new($value)),
909 )
910 }};
911}
912
913#[macro_export]
918macro_rules! i64_slice {
919 ($name: literal, $value: expr) => {
920 nsi::Arg::new($name, nsi::ArgData::from(nsi::I64Slice::new($value)))
921 };
922 ($name: path, $value: expr) => {{
923 const __ATTR_CHECK: $crate::Attribute<[i64]> = $name;
924 nsi::Arg::new(
925 __ATTR_CHECK.name(),
926 nsi::ArgData::from(nsi::I64Slice::new($value)),
927 )
928 }};
929}
930
931#[macro_export]
936macro_rules! color {
937 ($name: literal, $value: expr) => {
938 nsi::Arg::new($name, nsi::ArgData::from(nsi::Color::new($value)))
939 };
940 ($name: path, $value: expr) => {{
941 const __ATTR_CHECK: $crate::Attribute<$crate::Color3F32> = $name;
942 nsi::Arg::new(
943 __ATTR_CHECK.name(),
944 nsi::ArgData::from(nsi::Color::new($value)),
945 )
946 }};
947}
948
949#[macro_export]
954macro_rules! color_slice {
955 ($name: literal, $value: expr) => {
956 nsi::Arg::new($name, nsi::ArgData::from(nsi::ColorSlice::new($value)))
957 };
958 ($name: path, $value: expr) => {{
959 const __ATTR_CHECK: $crate::Attribute<[$crate::Color3F32]> = $name;
960 nsi::Arg::new(
961 __ATTR_CHECK.name(),
962 nsi::ArgData::from(nsi::ColorSlice::new($value)),
963 )
964 }};
965}
966
967#[macro_export]
972macro_rules! point {
973 ($name: literal, $value: expr) => {
974 nsi::Arg::new($name, nsi::ArgData::from(nsi::Point::new($value)))
975 };
976 ($name: path, $value: expr) => {{
977 const __ATTR_CHECK: $crate::Attribute<$crate::Point3F32> = $name;
978 nsi::Arg::new(
979 __ATTR_CHECK.name(),
980 nsi::ArgData::from(nsi::Point::new($value)),
981 )
982 }};
983}
984
985#[macro_export]
992macro_rules! point_slice {
993 ($name: literal, $value: expr) => {
995 nsi::Arg::new($name, nsi::ArgData::from(nsi::PointSlice::new($value)))
996 };
997 ($name: path, $value: expr) => {{
999 const __ATTR_CHECK: $crate::Attribute<[$crate::Point3F32]> = $name;
1000 nsi::Arg::new(
1001 __ATTR_CHECK.name(),
1002 nsi::ArgData::from(nsi::PointSlice::new($value)),
1003 )
1004 }};
1005}
1006
1007#[macro_export]
1022macro_rules! point4_f32_slice {
1023 ($name: literal, $value: expr) => {
1025 nsi::Arg::new(
1026 $name,
1027 nsi::ArgData::from(nsi::Point4F32Slice::new($value)),
1028 )
1029 };
1030 ($name: path, $value: expr) => {{
1032 const __ATTR_CHECK: $crate::Attribute<[$crate::Point4F32]> = $name;
1033 nsi::Arg::new(
1034 __ATTR_CHECK.name(),
1035 nsi::ArgData::from(nsi::Point4F32Slice::new($value)),
1036 )
1037 }};
1038}
1039
1040#[macro_export]
1045macro_rules! vector {
1046 ($name: literal, $value: expr) => {
1047 nsi::Arg::new($name, nsi::ArgData::from(nsi::Vector::new($value)))
1048 };
1049 ($name: path, $value: expr) => {{
1050 const __ATTR_CHECK: $crate::Attribute<$crate::Vector3F32> = $name;
1051 nsi::Arg::new(
1052 __ATTR_CHECK.name(),
1053 nsi::ArgData::from(nsi::Vector::new($value)),
1054 )
1055 }};
1056}
1057
1058#[macro_export]
1063macro_rules! vector_slice {
1064 ($name: literal, $value: expr) => {
1065 nsi::Arg::new($name, nsi::ArgData::from(nsi::VectorSlice::new($value)))
1066 };
1067 ($name: path, $value: expr) => {{
1068 const __ATTR_CHECK: $crate::Attribute<[$crate::Vector3F32]> = $name;
1069 nsi::Arg::new(
1070 __ATTR_CHECK.name(),
1071 nsi::ArgData::from(nsi::VectorSlice::new($value)),
1072 )
1073 }};
1074}
1075
1076#[macro_export]
1081macro_rules! normal {
1082 ($name: literal, $value: expr) => {
1083 nsi::Arg::new($name, nsi::ArgData::from(nsi::Normal::new($value)))
1084 };
1085 ($name: path, $value: expr) => {{
1086 const __ATTR_CHECK: $crate::Attribute<$crate::Normal3F32> = $name;
1087 nsi::Arg::new(
1088 __ATTR_CHECK.name(),
1089 nsi::ArgData::from(nsi::Normal::new($value)),
1090 )
1091 }};
1092}
1093
1094#[macro_export]
1099macro_rules! normal_slice {
1100 ($name: literal, $value: expr) => {
1101 nsi::Arg::new($name, nsi::ArgData::from(nsi::NormalSlice::new($value)))
1102 };
1103 ($name: path, $value: expr) => {{
1104 const __ATTR_CHECK: $crate::Attribute<[$crate::Normal3F32]> = $name;
1105 nsi::Arg::new(
1106 __ATTR_CHECK.name(),
1107 nsi::ArgData::from(nsi::NormalSlice::new($value)),
1108 )
1109 }};
1110}
1111
1112#[macro_export]
1118macro_rules! matrix_f32 {
1119 ($name: literal, $value: expr) => {
1120 nsi::Arg::new($name, nsi::ArgData::from(nsi::MatrixF32::new($value)))
1121 };
1122 ($name: path, $value: expr) => {{
1123 const __ATTR_CHECK: $crate::Attribute<$crate::Matrix4F32> = $name;
1124 nsi::Arg::new(
1125 __ATTR_CHECK.name(),
1126 nsi::ArgData::from(nsi::MatrixF32::new($value)),
1127 )
1128 }};
1129}
1130
1131#[macro_export]
1137macro_rules! matrix_f32_slice {
1138 ($name: literal, $value: expr) => {
1139 nsi::Arg::new(
1140 $name,
1141 nsi::ArgData::from(nsi::MatrixF32Slice::new($value)),
1142 )
1143 };
1144 ($name: path, $value: expr) => {{
1145 const __ATTR_CHECK: $crate::Attribute<[$crate::Matrix4F32]> = $name;
1146 nsi::Arg::new(
1147 __ATTR_CHECK.name(),
1148 nsi::ArgData::from(nsi::MatrixF32Slice::new($value)),
1149 )
1150 }};
1151}
1152
1153#[macro_export]
1177macro_rules! matrix_f64 {
1178 ($name: literal, $value: expr) => {
1179 nsi::Arg::new($name, nsi::ArgData::from(nsi::MatrixF64::new($value)))
1180 };
1181 ($name: path, $value: expr) => {{
1182 const __ATTR_CHECK: $crate::Attribute<$crate::Matrix4F64> = $name;
1183 nsi::Arg::new(
1184 __ATTR_CHECK.name(),
1185 nsi::ArgData::from(nsi::MatrixF64::new($value)),
1186 )
1187 }};
1188}
1189
1190#[macro_export]
1196macro_rules! matrix_f64_slice {
1197 ($name: literal, $value: expr) => {
1198 nsi::Arg::new(
1199 $name,
1200 nsi::ArgData::from(nsi::MatrixF64Slice::new($value)),
1201 )
1202 };
1203 ($name: path, $value: expr) => {{
1204 const __ATTR_CHECK: $crate::Attribute<[$crate::Matrix4F64]> = $name;
1205 nsi::Arg::new(
1206 __ATTR_CHECK.name(),
1207 nsi::ArgData::from(nsi::MatrixF64Slice::new($value)),
1208 )
1209 }};
1210}
1211
1212#[macro_export]
1224macro_rules! string {
1225 ($name: literal, $value: expr) => {
1226 nsi::Arg::new($name, nsi::ArgData::from(nsi::String::new($value)))
1227 };
1228 ($name: path, $value: expr) => {{
1229 const __ATTR_CHECK: $crate::Attribute<&'static str> = $name;
1230 nsi::Arg::new(
1231 __ATTR_CHECK.name(),
1232 nsi::ArgData::from(nsi::String::new($value)),
1233 )
1234 }};
1235}
1236
1237#[macro_export]
1254macro_rules! string_slice {
1255 ($name: literal, $value: expr) => {
1256 nsi::Arg::new($name, nsi::ArgData::from(nsi::StringSlice::new($value)))
1257 };
1258 ($name: path, $value: expr) => {{
1259 const __ATTR_CHECK: $crate::Attribute<[&'static str]> = $name;
1260 nsi::Arg::new(
1261 __ATTR_CHECK.name(),
1262 nsi::ArgData::from(nsi::StringSlice::new($value)),
1263 )
1264 }};
1265}
1266
1267#[macro_export]
1276macro_rules! reference {
1277 ($name: tt, $value: expr) => {
1278 nsi::Arg::new($name, nsi::ArgData::from(nsi::Reference::new($value)))
1279 };
1280}
1281
1282#[macro_export]
1288macro_rules! reference_stable {
1289 ($name: tt, $value: expr) => {
1290 nsi::Arg::new(
1291 $name,
1292 nsi::ArgData::from(unsafe { nsi::Reference::from_stable($value) }),
1293 )
1294 };
1295}
1296
1297#[macro_export]
1299macro_rules! reference_slice {
1300 ($name: tt, $value: expr) => {
1301 nsi::Arg::new(
1302 $name,
1303 nsi::ArgData::from(nsi::ReferenceSlice::new($value)),
1304 )
1305 };
1306}
1307
1308#[macro_export]
1310macro_rules! callback {
1311 ($name: tt, $value: expr) => {
1312 nsi::Arg::new($name, nsi::ArgData::from(nsi::Callback::new($value)))
1313 };
1314}
1315
1316#[cfg(test)]
1317mod tests {
1318 use super::*;
1319
1320 #[test]
1324 fn array_len_divides_element_count() {
1325 let resolution = [1280, 720];
1326 let args =
1327 [
1328 Arg::new(
1329 "resolution",
1330 ArgData::from(I32Slice::new(&resolution)),
1331 )
1332 .array_len(const { NonZeroUsize::new(2).unwrap() }),
1333 ];
1334
1335 let (len, _ptr, params) = to_c_param_vec(Some(&args));
1336
1337 assert_eq!(1, len);
1338 assert_eq!(2, params[0].arraylength);
1339 assert_eq!(1, params[0].count);
1340 }
1341
1342 #[test]
1344 fn default_array_len_is_one() {
1345 let resolution = [1280, 720];
1346 let args = [Arg::new(
1347 "resolution",
1348 ArgData::from(I32Slice::new(&resolution)),
1349 )];
1350
1351 let (_len, _ptr, params) = to_c_param_vec(Some(&args));
1352
1353 assert_eq!(1, params[0].arraylength);
1354 assert_eq!(2, params[0].count);
1355 }
1356}
1357
1358#[cfg(test)]
1368mod pointer_marshalling_tests {
1369 use super::*;
1370
1371 fn value_read_by_renderer(param: &NSIParam) -> *const c_void {
1374 assert_eq!(DataType::Reference as i32, param.type_);
1375 assert_eq!(1, param.count);
1376 unsafe { *(param.data as *const *const c_void) }
1379 }
1380
1381 #[test]
1382 fn reference_marshals_the_address_not_the_contents() {
1383 let payload = Box::new(0xdead_beef_cafe_f00d_u64);
1385 let address = &*payload as *const u64 as *const c_void;
1386
1387 let args =
1388 [Arg::new("payload", ArgData::from(Reference::new(&payload)))];
1389 let (_, _, params) = to_c_param_vec(Some(&args));
1390
1391 assert_eq!(
1392 address,
1393 value_read_by_renderer(¶ms[0]),
1394 "the renderer must receive the payload's address; receiving \
1395 its first eight bytes means one dereference too few in \
1396 `Reference::as_c_ptr`"
1397 );
1398 }
1399
1400 #[test]
1401 fn callback_marshals_the_pointer_not_its_target() {
1402 struct KnownPtr(*const c_void);
1403 impl CallbackPtr for KnownPtr {
1404 fn to_ptr(self) -> *const c_void {
1405 self.0
1406 }
1407
1408 unsafe fn drop_ptr(_ptr: *const c_void) {
1409 }
1411 }
1412
1413 let target = Box::new(0x1122_3344_5566_7788_u64);
1414 let handed_to_nsi = &*target as *const u64 as *const c_void;
1415
1416 let args = [Arg::new(
1417 "callback",
1418 ArgData::from(Callback::new(KnownPtr(handed_to_nsi))),
1419 )];
1420 let (_, _, params) = to_c_param_vec(Some(&args));
1421
1422 assert_eq!(
1423 handed_to_nsi,
1424 value_read_by_renderer(¶ms[0]),
1425 "the renderer must receive the pointer we handed to ɴsɪ, not \
1426 the bytes it points at"
1427 );
1428 }
1429}