1use std::{marker::PhantomData, ops::{Deref, DerefMut}};
3
4
5#[macro_export]
11#[doc(hidden)]
12macro_rules! mj_view_indices {
13 ($id:expr, $addr_map:expr, $njnt:expr, $max_n:expr) => {
14 {
15 let start_addr = *$addr_map.add($id) as isize;
16 if start_addr == -1 {
17 (0, 0)
18 }
19 else
20 {
21 let end_addr = if $id + 1 < $njnt as usize {*$addr_map.add($id as usize + 1) as usize} else {$max_n as usize};
22 let n = end_addr - start_addr as usize;
23 (start_addr as usize, n)
24 }
25 }
26 };
27}
28
29#[macro_export]
31#[doc(hidden)]
32macro_rules! mj_model_nx_to_mapping {
33 ($model_ffi:ident, nq) => {
34 $model_ffi.jnt_qposadr
35 };
36
37 ($model_ffi:ident, nv) => {
38 $model_ffi.jnt_dofadr
39 };
40
41 ($model_ffi:ident, nsensordata) => {
42 $model_ffi.sensor_adr
43 };
44 ($model_ffi:ident, ntupledata) => {
45 $model_ffi.tuple_adr
46 };
47 ($model_ffi:ident, ntexdata) => {
48 $model_ffi.tex_adr
49 };
50 ($model_ffi:ident, nnumericdata) => {
51 $model_ffi.numeric_adr
52 };
53 ($model_ffi:ident, nhfielddata) => {
54 $model_ffi.hfield_adr
55 };
56}
57
58
59#[macro_export]
61#[doc(hidden)]
62macro_rules! mj_model_nx_to_nitem {
63 ($model_ffi:ident, nq) => {
64 $model_ffi.njnt
65 };
66
67 ($model_ffi:ident, nv) => {
68 $model_ffi.njnt
69 };
70
71 ($model_ffi:ident, nsensordata) => {
72 $model_ffi.nsensor
73 };
74 ($model_ffi:ident, ntupledata) => {
75 $model_ffi.ntuple
76 };
77 ($model_ffi:ident, ntexdata) => {
78 $model_ffi.ntex
79 };
80 ($model_ffi:ident, nnumericdata) => {
81 $model_ffi.nnumeric
82 };
83 ($model_ffi:ident, nhfielddata) => {
84 $model_ffi.nhfield
85 };
86}
87
88#[derive(Debug)]
96pub struct PointerViewMut<'d, T> {
97 ptr: *mut T,
98 len: usize,
99 phantom: PhantomData<&'d mut ()>
100}
101
102impl<'d, T> PointerViewMut<'d, T> {
103 pub(crate) fn new(ptr: *mut T, len: usize) -> Self {
104 Self {ptr, len, phantom: PhantomData}
105 }
106
107 #[allow(unused)]
108 pub(crate) unsafe fn set_len(&mut self, len: usize) {
109 self.len = len;
110 }
111}
112
113impl<T> PartialEq for PointerViewMut<'_, T> {
115 fn eq(&self, other: &Self) -> bool {
116 self.ptr == other.ptr }
118}
119
120impl<T> Deref for PointerViewMut<'_, T> {
121 type Target = [T];
122 fn deref(&self) -> &Self::Target {
123 unsafe { std::slice::from_raw_parts(self.ptr, self.len) }
124 }
125}
126
127impl<T> DerefMut for PointerViewMut<'_, T> {
128 fn deref_mut(&mut self) -> &mut Self::Target {
129 unsafe { std::slice::from_raw_parts_mut(self.ptr, self.len) }
130 }
131}
132
133#[derive(Debug)]
141pub struct PointerView<'d, T> {
142 ptr: *const T,
143 len: usize,
144 phantom: PhantomData<&'d ()>
145}
146
147impl<'d, T> PointerView<'d, T> {
148 pub(crate) fn new(ptr: *const T, len: usize) -> Self {
149 Self {ptr, len, phantom: PhantomData}
150 }
151
152 #[allow(unused)]
153 pub(crate) unsafe fn set_len(&mut self, len: usize) {
154 self.len = len;
155 }
156}
157
158impl<T> PartialEq for PointerView<'_, T> {
160 fn eq(&self, other: &Self) -> bool {
161 self.ptr == other.ptr }
163}
164
165impl<T> Deref for PointerView<'_, T> {
166 type Target = [T];
167 fn deref(&self) -> &Self::Target {
168 unsafe { std::slice::from_raw_parts(self.ptr, self.len) }
169 }
170}
171
172#[macro_export]
178#[doc(hidden)]
179macro_rules! eval_or_expand {
180 (@eval $(true)? { $($data:tt)* } ) => { $($data)* };
181 (@eval false { $($data:tt)* } ) => {};
182}
183
184
185#[macro_export]
191#[doc(hidden)]
192macro_rules! view_creator {
193 ($self:expr, $view:ident, $data:expr, [$($field:ident),*], [$($opt_field:ident),*], $ptr_view:expr) => {
195 unsafe {
196 $view {
197 $(
198 $field: $ptr_view($data.$field.add($self.$field.0).cast(), $self.$field.1),
199 )*
200 $(
201 $opt_field: if $self.$opt_field.1 > 0 {
202 Some($ptr_view($data.$opt_field.add($self.$opt_field.0).cast(), $self.$opt_field.1))
203 } else {None},
204 )*
205 }
206 }
207 };
208
209 ($self:expr, $view:ident, $data:expr, $prefix:ident, [$($field:ident),*], [$($opt_field:ident),*], $ptr_view:expr) => {
210 paste::paste! {
211 unsafe {
212 $view {
213 $(
214 $field: $ptr_view($data.[<$prefix $field>].add($self.$field.0).cast(), $self.$field.1),
215 )*
216 $(
217 $opt_field: if $self.$opt_field.1 > 0 {
218 Some($ptr_view($data.[<$prefix $opt_field>].add($self.$opt_field.0).cast(), $self.$opt_field.1))
219 } else {None},
220 )*
221 }
222 }
223 }
224 };
225}
226
227
228#[doc(hidden)]
233#[macro_export]
234macro_rules! info_method {
235 ($info_type:ident, $ffi:expr, $type_:ident, [$($attr:ident: $len:expr),*], [$($attr_ffi:ident: $len_ffi:ident $(* $multiplier:expr)?),*], [$($attr_dyn:ident: $ffi_len_dyn:expr),*]) => {
236 paste::paste! {
237 #[doc = concat!(
238 "Obtains a [`", stringify!([<Mj $type_:camel $info_type Info>]), "`] struct containing information about the name, id, and ",
239 "indices required for obtaining references to the correct locations in [`Mj", stringify!($info_type), "`]. ",
240 "The actual view can be obtained via [`", stringify!([<Mj $type_:camel $info_type Info>]), "::view`].\n",
241 "# Panics\n",
242 "A panic will occur if `name` contains `\\0` characters."
243 )]
244 pub fn $type_(&self, name: &str) -> Option<[<Mj $type_:camel $info_type Info>]> {
245 let c_name = CString::new(name).unwrap();
246 let ffi = self.$ffi;
247 let id = unsafe { mj_name2id(ffi, MjtObj::[<mjOBJ_ $type_:upper>] as i32, c_name.as_ptr())};
248 if id == -1 { return None;
250 }
251
252 let id = id as usize;
253 $(
254 let $attr = (id * $len, $len);
255 )*
256
257 $(
258 let $attr_ffi = (id * ffi.$len_ffi as usize $( * $multiplier)*, ffi.$len_ffi as usize $( * $multiplier)*);
259 )*
260
261 $(
262 let $attr_dyn = unsafe { mj_view_indices!(
263 id,
264 mj_model_nx_to_mapping!(ffi, $ffi_len_dyn),
265 mj_model_nx_to_nitem!(ffi, $ffi_len_dyn),
266 ffi.$ffi_len_dyn
267 ) };
268 )*
269
270 Some([<Mj $type_:camel $info_type Info>] {name: name.to_string(), id, $($attr,)* $($attr_ffi,)* $($attr_dyn),*})
271 }
272 }
273 }
274}
275
276
277#[doc(hidden)]
296#[macro_export]
297macro_rules! info_with_view {
298 ($info_type:ident, $name:ident, $prefix:ident, [$($attr:ident: $type_:ty),*], [$($opt_attr:ident: $type_opt:ty),*]$(,$generics:ty: $bound:ty)?) => {
302 paste::paste! {
303 #[doc = "Stores information required to create views to [`Mj" $info_type "`] arrays corresponding to a " $name "."]
304 #[allow(non_snake_case)]
305 pub struct [<Mj $name:camel $info_type Info>] {
306 pub name: String,
307 pub id: usize,
308 $(
309 $attr: (usize, usize),
310 )*
311 $(
312 $opt_attr: (usize, usize),
313 )*
314 }
315
316 impl [<Mj $name:camel $info_type Info>] {
317 #[doc = "Returns a mutable view to the correct fields in [`Mj" $info_type "`]"]
318 pub fn view_mut $(<$generics: $bound>)?(&self, [<$info_type:lower>]: &mut [<Mj $info_type>]$(<$generics>)?) -> [<Mj $name:camel $info_type ViewMut>]<'_> {
319 view_creator!(self, [<Mj $name:camel $info_type ViewMut>], [<$info_type:lower>].ffi(), $prefix, [$($attr),*], [$($opt_attr),*], crate::util::PointerViewMut::new)
320 }
321
322 #[doc = "Returns a view to the correct fields in [`Mj" $info_type "`]"]
323 pub fn view $(<$generics: $bound>)?(&self, [<$info_type:lower>]: &[<Mj $info_type>]$(<$generics>)?) -> [<Mj $name:camel $info_type View>]<'_> {
324 view_creator!(self, [<Mj $name:camel $info_type View>], [<$info_type:lower>].ffi(), $prefix, [$($attr),*], [$($opt_attr),*], crate::util::PointerView::new)
325 }
326 }
327
328 #[doc = "A mutable view to " $name " variables of [`Mj" $info_type "`]."]
329 #[allow(non_snake_case)]
330 pub struct [<Mj $name:camel $info_type ViewMut>]<'d> {
331 $(
332 pub $attr: crate::util::PointerViewMut<'d, $type_>,
333 )*
334 $(
335 pub $opt_attr: Option<crate::util::PointerViewMut<'d, $type_opt>>,
336 )*
337 }
338
339 impl [<Mj $name:camel $info_type ViewMut>]<'_> {
340 pub fn zero(&mut self) {
342 $(
343 self.$attr.fill(unsafe { std::mem::zeroed() });
344 )*
345 $(
346 if let Some(x) = &mut self.$opt_attr {
347 x.fill(unsafe { std::mem::zeroed() });
348 }
349 )*
350 }
351 }
352
353 #[doc = "An immutable view to " $name " variables of [`Mj" $info_type "`]."]
354 #[allow(non_snake_case)]
355 pub struct [<Mj $name:camel $info_type View>]<'d> {
356 $(
357 pub $attr: crate::util::PointerView<'d, $type_>,
358 )*
359 $(
360 pub $opt_attr: Option<crate::util::PointerView<'d, $type_opt>>,
361 )*
362 }
363 }
364 };
365
366 ($info_type:ident, $name:ident, [$($attr:ident: $type_:ty),*], [$($opt_attr:ident: $type_opt:ty),*]$(,$generics:ty: $bound:ty)?) => {
368 paste::paste! {
369 #[doc = "Stores information required to create views to [`Mj" $info_type "`] arrays corresponding to a " $name "."]
370 #[allow(non_snake_case)]
371 pub struct [<Mj $name:camel $info_type Info>] {
372 pub name: String,
373 pub id: usize,
374 $(
375 $attr: (usize, usize),
376 )*
377 $(
378 $opt_attr: (usize, usize),
379 )*
380 }
381
382 impl [<Mj $name:camel $info_type Info>] {
383 #[doc = "Returns a mutable view to the correct fields in [`Mj" $info_type "`]"]
384 pub fn view_mut $(<$generics: $bound>)?(&self, [<$info_type:lower>]: &mut [<Mj $info_type>]$(<$generics>)?) -> [<Mj $name:camel $info_type ViewMut>]<'_> {
385 view_creator!(self, [<Mj $name:camel $info_type ViewMut>], [<$info_type:lower>].ffi(), [$($attr),*], [$($opt_attr),*], crate::util::PointerViewMut::new)
386 }
387
388 #[doc = "Returns a view to the correct fields in [`Mj" $info_type "`]"]
389 pub fn view $(<$generics: $bound>)?(&self, [<$info_type:lower>]: &[<Mj $info_type>]$(<$generics>)?) -> [<Mj $name:camel $info_type View>]<'_> {
390 view_creator!(self, [<Mj $name:camel $info_type View>], [<$info_type:lower>].ffi(), [$($attr),*], [$($opt_attr),*], crate::util::PointerView::new)
391 }
392 }
393
394 #[doc = "A mutable view to " $name " variables of [`Mj" $info_type "`]."]
395 #[allow(non_snake_case)]
396 pub struct [<Mj $name:camel $info_type ViewMut>]<'d> {
397 $(
398 pub $attr: crate::util::PointerViewMut<'d, $type_>,
399 )*
400 $(
401 pub $opt_attr: Option<crate::util::PointerViewMut<'d, $type_opt>>,
402 )*
403 }
404
405 impl [<Mj $name:camel $info_type ViewMut>]<'_> {
406 pub fn zero(&mut self) {
408 $(
409 self.$attr.fill(unsafe { std::mem::zeroed() });
410 )*
411 $(
412 if let Some(x) = &mut self.$opt_attr {
413 x.fill(unsafe { std::mem::zeroed() });
414 }
415 )*
416 }
417 }
418
419 #[doc = "An immutable view to " $name " variables of [`Mj" $info_type "`]."]
420 #[allow(non_snake_case)]
421 pub struct [<Mj $name:camel $info_type View>]<'d> {
422 $(
423 pub $attr: crate::util::PointerView<'d, $type_>,
424 )*
425 $(
426 pub $opt_attr: Option<crate::util::PointerView<'d, $type_opt>>,
427 )*
428 }
429 }
430 };
431}
432
433
434#[doc(hidden)]
435#[macro_export]
436macro_rules! getter_setter {
437 (get, [$($([$ffi:ident])? $name:ident $(+ $symbol:tt)?: bool; $comment:expr);* $(;)?]) => {paste::paste!{
438 $(
439 #[doc = concat!("Check ", $comment)]
440 pub fn [<$name:camel:snake $($symbol)?>](&self) -> bool {
441 self$(.$ffi())?.$name == 1
442 }
443 )*
444 }};
445
446 (get, [$($([$ffi:ident $(,$ffi_mut:ident)?])? $((allow_mut = $cfg_mut:literal))? $name:ident $(+ $symbol:tt)?: & $type:ty; $comment:expr);* $(;)?]) => {paste::paste!{
447 $(
448 #[doc = concat!("Return an immutable reference to ", $comment)]
449 pub fn [<$name:camel:snake $($symbol)?>](&self) -> &$type {
450 &self$(.$ffi())?.$name
451 }
452
453 crate::eval_or_expand! {
454 @eval $($cfg_mut)? {
455 #[doc = concat!("Return a mutable reference to ", $comment)]
456 pub fn [<$name:camel:snake _mut>](&mut self) -> &mut $type {
457 #[allow(unused_unsafe)]
458 unsafe { &mut self$(.$($ffi_mut())?)?.$name }
459 }
460 }
461 }
462 )*
463 }};
464
465 (get, [$($([$ffi:ident])? $name:ident $(+ $symbol:tt)?: $type:ty; $comment:expr);* $(;)?]) => {paste::paste!{
466 $(
467 #[doc = concat!("Return value of ", $comment)]
468 pub fn [<$name:camel:snake $($symbol)?>](&self) -> $type {
469 self$(.$ffi())?.$name.into()
470 }
471 )*
472 }};
473
474 (set, [$($([$ffi_mut:ident])? $name:ident: $type:ty; $comment:expr);* $(;)?]) => {
475 paste::paste!{
476 $(
477 #[doc = concat!("Set ", $comment)]
478 pub fn [<set_ $name:camel:snake>](&mut self, value: $type) {
479 #[allow(unused_unsafe)]
480 unsafe { self$(.$ffi_mut())?.$name = value.into() };
481 }
482 )*
483 }
484 };
485
486 (force!, get, [$($([$ffi:ident])? $name:ident $(+ $symbol:tt)? : $type:ty; $comment:expr);* $(;)?]) => {paste::paste!{
488 $(
489 #[doc = concat!("Return value of ", $comment)]
490 pub fn [<$name:camel:snake $($symbol)?>](&self) -> $type {
491 unsafe { std::mem::transmute(self$(.$ffi())?.$name) }
492 }
493 )*
494 }};
495
496 (force!, set, [$($([$ffi_mut:ident])? $name:ident: $type:ty; $comment:expr);* $(;)?]) => {
497 paste::paste!{
498 $(
499 #[doc = concat!("Set ", $comment)]
500 pub fn [<set_ $name:camel:snake>](&mut self, value: $type) {
501 #[allow(unnecessary_transmutes)]
502 unsafe { self$(.$ffi_mut())?.$name = std::mem::transmute(value) };
503 }
504 )*
505 }
506 };
507
508 (force!, with, [$($([$ffi_mut:ident])? $name:ident: $type:ty; $comment:expr);* $(;)?]) => {
510 paste::paste!{
511 $(
512 #[doc = concat!("Builder method for setting ", $comment)]
513 pub fn [<with_ $name:camel:snake>](mut self, value: $type) -> Self {
514 #[allow(unnecessary_transmutes)]
515 unsafe { self$(.$ffi_mut())?.$name = std::mem::transmute(value) };
516 self
517 }
518 )*
519 }
520 };
521
522 (force!, [&] with, [$($([$ffi_mut:ident])? $name:ident: $type:ty; $comment:expr);* $(;)?]) => {
523 paste::paste!{
524 $(
525 #[doc = concat!("Builder method for setting ", $comment)]
526 pub fn [<with_ $name:camel:snake>](&mut self, value: $type) -> &mut Self {
527 #[allow(unnecessary_transmutes)]
528 unsafe { self$(.$ffi_mut())?.$name = std::mem::transmute(value) };
529 self
530 }
531 )*
532 }
533 };
534
535 (with, [$($([$ffi_mut:ident])? $name:ident: $type:ty; $comment:expr);* $(;)?]) => {
536 paste::paste!{
537 $(
538 #[doc = concat!("Builder method for setting ", $comment)]
539 pub fn [<with_ $name:camel:snake>](mut self, value: $type) -> Self {
540 #[allow(unused_unsafe)]
541 unsafe { self$(.$ffi_mut())?.$name = value.into() };
542 self
543 }
544 )*
545 }
546 };
547
548 ([&] with, [$($([$ffi_mut:ident])? $name:ident: $type:ty; $comment:expr);* $(;)?]) => {
549 paste::paste!{
550 $(
551 #[doc = concat!("Builder method for setting ", $comment)]
552 pub fn [<with_ $name:camel:snake>](&mut self, value: $type) -> &mut Self {
553 #[allow(unused_unsafe)]
554 unsafe { self$(.$ffi_mut())?.$name = value.into() };
555 self
556 }
557 )*
558 }
559 };
560
561 (force!, get, set, [ $($([$ffi: ident, $ffi_mut:ident])? $name:ident $(+ $symbol:tt)? : $type:ty ; $comment:expr );* $(;)?]) => {
564 $crate::getter_setter!(force!, get, [ $($([$ffi])? $name $(+ $symbol)? : $type ; $comment );* ]);
565 $crate::getter_setter!(force!, set, [ $($([$ffi_mut])? $name : $type ; $comment );* ]);
566 };
567
568 (get, set, [ $($([$ffi: ident, $ffi_mut:ident])? $name:ident $(+ $symbol:tt)? : bool ; $comment:expr );* $(;)?]) => {
569 $crate::getter_setter!(get, [ $($([$ffi])? $name $(+ $symbol)? : bool ; $comment );* ]);
570 $crate::getter_setter!(set, [ $($([$ffi_mut])? $name : bool ; $comment );* ]);
571 };
572
573 (get, set, [ $($([$ffi: ident, $ffi_mut:ident])? $name:ident $(+ $symbol:tt)? : $type:ty ; $comment:expr );* $(;)?]) => {
574 $crate::getter_setter!(get, [ $($([$ffi])? $name $(+ $symbol)? : $type ; $comment );* ]);
575 $crate::getter_setter!(set, [ $($([$ffi_mut])? $name : $type ; $comment );* ]);
576 };
577
578 ($([$token:tt])? with, get, set, [ $($([$ffi: ident, $ffi_mut:ident])? $name:ident $(+ $symbol:tt)? : bool ; $comment:expr );* $(;)?]) => {
580 $crate::getter_setter!(get, [ $($([$ffi])? $name $(+ $symbol)? : bool ; $comment );* ]);
581 $crate::getter_setter!(set, [ $($([$ffi_mut])? $name : bool ; $comment );* ]);
582 $crate::getter_setter!($([$token])? with, [ $($([$ffi_mut])? $name : bool ; $comment );* ]);
583 };
584
585 ($([$token:tt])? with, get, set, [ $($([$ffi: ident, $ffi_mut:ident])? $name:ident $(+ $symbol:tt)? : $type:ty ; $comment:expr );* $(;)?]) => {
586 $crate::getter_setter!(get, [ $($([$ffi])? $name $(+ $symbol)?: $type ; $comment );* ]);
587 $crate::getter_setter!(set, [ $($([$ffi_mut])? $name : $type ; $comment );* ]);
588 $crate::getter_setter!($([$token])? with, [ $($([$ffi_mut])? $name : $type ; $comment );* ]);
589 };
590
591 (force!, $([$token:tt])? with, get, set, [ $($([$ffi: ident, $ffi_mut:ident])? $name:ident $(+ $symbol:tt)? : $type:ty ; $comment:expr );* $(;)?]) => {
592 $crate::getter_setter!(force!, get, [$($([$ffi])? $name $(+ $symbol)? : $type ; $comment );* ]);
593 $crate::getter_setter!(force!, set, [$($([$ffi_mut])? $name : $type ; $comment );* ]);
594 $crate::getter_setter!(force!, $([$token])? with, [$($([$ffi_mut])? $name : $type ; $comment );* ]);
595 };
596
597 ($([$token:tt])? with, get, [$( $([$ffi: ident, $ffi_mut:ident])? $((allow_mut = $allow_mut:literal))? $name:ident $(+ $symbol:tt)? : & $type:ty ; $comment:expr );* $(;)?]) => {
598 $crate::getter_setter!(get, [ $($([$ffi, $ffi_mut])? $((allow_mut = $allow_mut))? $name $(+ $symbol)? : & $type ; $comment );* ]);
599 $crate::getter_setter!($([$token])? with, [ $( $([$ffi_mut])? $name : $type ; $comment );* ]);
600 };
601}
602
603
604#[doc(hidden)]
605#[macro_export]
606macro_rules! builder_setters {
608 ($($name:ident: $type:ty; $comment:expr);* $(;)?) => {
609 $(
610 #[doc = concat!("Set ", $comment)]
611 pub fn $name(mut self, value: $type) -> Self {
612 self.$name = value;
613 self
614 }
615 )*
616 };
617}
618
619#[doc(hidden)]
635#[macro_export]
636macro_rules! array_slice_dyn {
637 ($($((allow_mut = $cfg_mut:literal))? $name:ident: $($as_ptr:ident $as_mut_ptr:ident)? &[$type:ty $([$cast:ident])?; $doc:literal; $($len_accessor:tt)*]),*) => {
639 paste::paste! {
640 $(
641 #[doc = concat!("Immutable slice of the ", $doc," array.")]
642 pub fn [<$name:camel:snake>](&self) -> &[$type] {
643 let length = self.$($len_accessor)* as usize;
644 if length == 0 {
645 return &[];
646 }
647 unsafe { std::slice::from_raw_parts(self.ffi().$name$(.$as_ptr())?$(.$cast())? as *const _, length) }
648 }
649
650 crate::eval_or_expand! {
651 @eval $($cfg_mut)? {
652 #[doc = concat!("Mutable slice of the ", $doc," array.")]
653 pub fn [<$name:camel:snake _mut>](&mut self) -> &mut [$type] {
654 let length = self.$($len_accessor)* as usize;
655 if length == 0 {
656 return &mut [];
657 }
658 unsafe { std::slice::from_raw_parts_mut(self.ffi_mut().$name$(.$as_mut_ptr())?$(.$cast())?, length) }
659 }
660 }
661 }
662 )*
663 }
664 };
665
666 (summed { $( $(allow_mut = $cfg_mut:literal)? $name:ident: &[$type:ty; $doc:literal; [$multiplier:literal ; ($($len_array:tt)*) ; ($($len_array_length:tt)*)]]),* }) => {
668 paste::paste! {
669 $(
670 #[doc = concat!("Immutable slice of the ", $doc," array.")]
671 pub fn [<$name:camel:snake>](&self) -> &[[$type; $multiplier]] {
672 let length_array_length = self.$($len_array_length)* as usize;
674 if length_array_length == 0 {
675 return &[];
676 }
677
678 let length = unsafe { std::slice::from_raw_parts(
679 self.$($len_array)*.cast(),
680 length_array_length
681 ).into_iter().sum::<u32>() as usize };
682
683 if length == 0 {
684 return &[];
685 }
686
687 unsafe { std::slice::from_raw_parts(self.ffi().$name.cast(), length) }
688 }
689
690 crate::eval_or_expand! {
691 @eval $($cfg_mut)? {
692 #[doc = concat!("Mutable slice of the ", $doc," array.")]
693 pub fn [<$name:camel:snake _mut>](&mut self) -> &mut [[$type; $multiplier]] {
694 let length_array_length = self.$($len_array_length)* as usize;
695 if length_array_length == 0 {
696 return &mut [];
697 }
698
699 let length = unsafe { std::slice::from_raw_parts(
700 self.$($len_array)*.cast(),
701 length_array_length
702 ).into_iter().sum::<u32>() as usize };
703
704 if length == 0 {
705 return &mut [];
706 }
707
708 unsafe { std::slice::from_raw_parts_mut(self.ffi_mut().$name.cast(), length) }
709 }
710 }
711 }
712 )*
713 }
714 };
715
716 (sublen_dep {$( $(allow_mut = $cfg_mut:literal)? $name:ident: $($as_ptr:ident $as_mut_ptr:ident)? &[[$type:ty; $($inner_len_accessor:tt)*] $([$cast:ident])?; $doc:literal; $($len_accessor:tt)*]),*}) => {
718 paste::paste! {
719 $(
720 #[doc = concat!("Immutable slice of the ", $doc," array.")]
721 pub fn [<$name:camel:snake>](&self) -> &[$type] {
722 let length = self.$($len_accessor)* as usize * self.$($inner_len_accessor)* as usize;
723 if length == 0 {
724 return &[];
725 }
726
727
728 unsafe { std::slice::from_raw_parts(self.ffi().$name$(.$as_ptr())?$(.$cast())? as *const _, length) }
729 }
730
731 crate::eval_or_expand! {
732 @eval $($cfg_mut)? {
733 #[doc = concat!("Mutable slice of the ", $doc," array.")]
734 pub fn [<$name:camel:snake _mut>](&mut self) -> &mut [$type] {
735 let length = self.$($len_accessor)* as usize * self.$($inner_len_accessor)* as usize;
736 if length == 0 {
737 return &mut [];
738 }
739 unsafe { std::slice::from_raw_parts_mut(self.ffi_mut().$name$(.$as_mut_ptr())?$(.$cast())?, length) }
740 }
741 }
742 }
743 )*
744 }
745 };
746}
747
748#[doc(hidden)]
750#[macro_export]
751macro_rules! c_str_as_str_method {
752 (raw {$( $name:ident : $comment:literal; )*}) => {
753 $(
754 #[doc = $comment]
755 pub fn $name(&self) -> &str {
756 unsafe {
757 let c_ptr = self.ffi().$name;
758 CStr::from_ptr(c_ptr).to_str().unwrap()
759 }
760 }
761 )*
762 };
763}
764
765#[doc(hidden)]
767#[macro_export]
768macro_rules! assert_relative_eq {
769 ($a:expr, $b:expr, epsilon = $eps:expr) => {{
770 let (a, b, eps) = ($a as f64, $b as f64, $eps as f64);
771 assert!((a - b).abs() <= eps, "left={:?} right={:?} eps={:?}", a, b, eps);
772 }};
773}