1use crate::core::{box3d_lock, callback_state};
2use crate::error::Result;
3use crate::types::{BodyId, ContactData, ContactId, JointId, Pos, ShapeId, Vec3, WorldTransform};
4use crate::world::World;
5use boxddd_sys::ffi;
6use std::ffi::c_void;
7
8#[derive(Copy, Clone)]
9pub struct BodyMove<'a>(&'a ffi::b3BodyMoveEvent);
15
16impl BodyMove<'_> {
17 pub fn body_id(&self) -> BodyId {
19 BodyId::from_raw(self.0.bodyId)
20 }
21
22 pub fn transform(&self) -> WorldTransform {
24 WorldTransform::from_raw(self.0.transform)
25 }
26
27 pub fn fell_asleep(&self) -> bool {
29 self.0.fellAsleep
30 }
31
32 pub fn raw_user_data(&self) -> *mut c_void {
37 self.0.userData
38 }
39}
40
41pub struct BodyMoveIter<'a>(std::slice::Iter<'a, ffi::b3BodyMoveEvent>);
46
47impl<'a> Iterator for BodyMoveIter<'a> {
48 type Item = BodyMove<'a>;
49
50 fn next(&mut self) -> Option<Self::Item> {
51 self.0.next().map(BodyMove)
52 }
53
54 fn size_hint(&self) -> (usize, Option<usize>) {
55 self.0.size_hint()
56 }
57}
58
59#[derive(Clone, Debug, PartialEq)]
60pub struct BodyMoveEvent {
65 pub body_id: BodyId,
67 pub transform: WorldTransform,
69 pub fell_asleep: bool,
71 pub raw_user_data: *mut c_void,
73}
74
75#[derive(Copy, Clone)]
76pub struct SensorBeginTouch<'a>(&'a ffi::b3SensorBeginTouchEvent);
81
82impl SensorBeginTouch<'_> {
83 pub fn sensor_shape(&self) -> ShapeId {
85 ShapeId::from_raw(self.0.sensorShapeId)
86 }
87
88 pub fn visitor_shape(&self) -> ShapeId {
90 ShapeId::from_raw(self.0.visitorShapeId)
91 }
92}
93
94#[derive(Copy, Clone)]
95pub struct SensorEndTouch<'a>(&'a ffi::b3SensorEndTouchEvent);
102
103impl SensorEndTouch<'_> {
104 pub fn sensor_shape(&self) -> ShapeId {
106 ShapeId::from_raw(self.0.sensorShapeId)
107 }
108
109 pub fn visitor_shape(&self) -> ShapeId {
111 ShapeId::from_raw(self.0.visitorShapeId)
112 }
113}
114
115pub struct SensorBeginIter<'a>(std::slice::Iter<'a, ffi::b3SensorBeginTouchEvent>);
120
121impl<'a> Iterator for SensorBeginIter<'a> {
122 type Item = SensorBeginTouch<'a>;
123
124 fn next(&mut self) -> Option<Self::Item> {
125 self.0.next().map(SensorBeginTouch)
126 }
127
128 fn size_hint(&self) -> (usize, Option<usize>) {
129 self.0.size_hint()
130 }
131}
132
133pub struct SensorEndIter<'a>(std::slice::Iter<'a, ffi::b3SensorEndTouchEvent>);
138
139impl<'a> Iterator for SensorEndIter<'a> {
140 type Item = SensorEndTouch<'a>;
141
142 fn next(&mut self) -> Option<Self::Item> {
143 self.0.next().map(SensorEndTouch)
144 }
145
146 fn size_hint(&self) -> (usize, Option<usize>) {
147 self.0.size_hint()
148 }
149}
150
151#[derive(Clone, Debug, PartialEq, Eq)]
152pub struct SensorBeginTouchEvent {
154 pub sensor_shape: ShapeId,
156 pub visitor_shape: ShapeId,
158}
159
160#[derive(Clone, Debug, PartialEq, Eq)]
161pub struct SensorEndTouchEvent {
163 pub sensor_shape: ShapeId,
165 pub visitor_shape: ShapeId,
167}
168
169#[derive(Clone, Debug, Default, PartialEq, Eq)]
170pub struct SensorEvents {
172 pub begin: Vec<SensorBeginTouchEvent>,
174 pub end: Vec<SensorEndTouchEvent>,
176}
177
178#[derive(Copy, Clone)]
179pub struct ContactBeginTouch<'a>(&'a ffi::b3ContactBeginTouchEvent);
184
185impl ContactBeginTouch<'_> {
186 pub fn shape_a(&self) -> ShapeId {
188 ShapeId::from_raw(self.0.shapeIdA)
189 }
190
191 pub fn shape_b(&self) -> ShapeId {
193 ShapeId::from_raw(self.0.shapeIdB)
194 }
195
196 pub fn contact_id(&self) -> ContactId {
201 ContactId::from_raw(self.0.contactId)
202 }
203}
204
205#[derive(Copy, Clone)]
206pub struct ContactEndTouch<'a>(&'a ffi::b3ContactEndTouchEvent);
212
213impl ContactEndTouch<'_> {
214 pub fn shape_a(&self) -> ShapeId {
218 ShapeId::from_raw(self.0.shapeIdA)
219 }
220
221 pub fn shape_b(&self) -> ShapeId {
225 ShapeId::from_raw(self.0.shapeIdB)
226 }
227
228 pub fn contact_id(&self) -> ContactId {
232 ContactId::from_raw(self.0.contactId)
233 }
234}
235
236#[derive(Copy, Clone)]
237pub struct ContactHit<'a>(&'a ffi::b3ContactHitEvent);
243
244impl ContactHit<'_> {
245 pub fn shape_a(&self) -> ShapeId {
247 ShapeId::from_raw(self.0.shapeIdA)
248 }
249
250 pub fn shape_b(&self) -> ShapeId {
252 ShapeId::from_raw(self.0.shapeIdB)
253 }
254
255 pub fn contact_id(&self) -> ContactId {
257 ContactId::from_raw(self.0.contactId)
258 }
259
260 pub fn point(&self) -> Pos {
262 Pos::from_raw(self.0.point)
263 }
264
265 pub fn normal(&self) -> Vec3 {
267 Vec3::from_raw(self.0.normal)
268 }
269
270 pub fn approach_speed(&self) -> f32 {
274 self.0.approachSpeed
275 }
276
277 pub fn user_material_id_a(&self) -> u64 {
279 self.0.userMaterialIdA
280 }
281
282 pub fn user_material_id_b(&self) -> u64 {
284 self.0.userMaterialIdB
285 }
286}
287
288pub struct ContactBeginIter<'a>(std::slice::Iter<'a, ffi::b3ContactBeginTouchEvent>);
293
294impl<'a> Iterator for ContactBeginIter<'a> {
295 type Item = ContactBeginTouch<'a>;
296
297 fn next(&mut self) -> Option<Self::Item> {
298 self.0.next().map(ContactBeginTouch)
299 }
300
301 fn size_hint(&self) -> (usize, Option<usize>) {
302 self.0.size_hint()
303 }
304}
305
306pub struct ContactEndIter<'a>(std::slice::Iter<'a, ffi::b3ContactEndTouchEvent>);
311
312impl<'a> Iterator for ContactEndIter<'a> {
313 type Item = ContactEndTouch<'a>;
314
315 fn next(&mut self) -> Option<Self::Item> {
316 self.0.next().map(ContactEndTouch)
317 }
318
319 fn size_hint(&self) -> (usize, Option<usize>) {
320 self.0.size_hint()
321 }
322}
323
324pub struct ContactHitIter<'a>(std::slice::Iter<'a, ffi::b3ContactHitEvent>);
329
330impl<'a> Iterator for ContactHitIter<'a> {
331 type Item = ContactHit<'a>;
332
333 fn next(&mut self) -> Option<Self::Item> {
334 self.0.next().map(ContactHit)
335 }
336
337 fn size_hint(&self) -> (usize, Option<usize>) {
338 self.0.size_hint()
339 }
340}
341
342#[derive(Clone, Debug, PartialEq, Eq)]
343pub struct ContactBeginTouchEvent {
345 pub shape_a: ShapeId,
347 pub shape_b: ShapeId,
349 pub contact_id: ContactId,
351}
352
353#[derive(Clone, Debug, PartialEq, Eq)]
354pub struct ContactEndTouchEvent {
356 pub shape_a: ShapeId,
358 pub shape_b: ShapeId,
360 pub contact_id: ContactId,
362}
363
364#[derive(Clone, Debug, PartialEq)]
365pub struct ContactHitEvent {
367 pub shape_a: ShapeId,
369 pub shape_b: ShapeId,
371 pub contact_id: ContactId,
373 pub point: Pos,
375 pub normal: Vec3,
377 pub approach_speed: f32,
379 pub user_material_id_a: u64,
381 pub user_material_id_b: u64,
383}
384
385#[derive(Clone, Debug, Default, PartialEq)]
386pub struct ContactEvents {
388 pub begin: Vec<ContactBeginTouchEvent>,
390 pub end: Vec<ContactEndTouchEvent>,
392 pub hit: Vec<ContactHitEvent>,
394}
395
396#[derive(Copy, Clone)]
397pub struct JointEventView<'a>(&'a ffi::b3JointEvent);
402
403impl JointEventView<'_> {
404 pub fn joint_id(&self) -> JointId {
406 JointId::from_raw(self.0.jointId)
407 }
408
409 pub fn raw_user_data(&self) -> *mut c_void {
414 self.0.userData
415 }
416}
417
418pub struct JointEventIter<'a>(std::slice::Iter<'a, ffi::b3JointEvent>);
423
424impl<'a> Iterator for JointEventIter<'a> {
425 type Item = JointEventView<'a>;
426
427 fn next(&mut self) -> Option<Self::Item> {
428 self.0.next().map(JointEventView)
429 }
430
431 fn size_hint(&self) -> (usize, Option<usize>) {
432 self.0.size_hint()
433 }
434}
435
436#[derive(Clone, Debug, PartialEq)]
437pub struct JointEvent {
439 pub joint_id: JointId,
441 pub raw_user_data: *mut c_void,
443}
444
445fn map_snapshot_into<T, U>(out: &mut Vec<U>, input: &[T], mut map: impl FnMut(&T) -> U) {
446 out.clear();
447 out.reserve(input.len());
448 out.extend(input.iter().map(|value| map(value)));
449}
450
451fn raw_event_slice<'a, T>(ptr: *const T, count: i32) -> &'a [T] {
452 if count > 0 && !ptr.is_null() {
453 unsafe { std::slice::from_raw_parts(ptr, count as usize) }
454 } else {
455 &[]
456 }
457}
458
459fn body_event_slice<'a>(raw: ffi::b3BodyEvents) -> &'a [ffi::b3BodyMoveEvent] {
460 raw_event_slice(raw.moveEvents, raw.moveCount)
461}
462
463fn sensor_begin_slice<'a>(raw: ffi::b3SensorEvents) -> &'a [ffi::b3SensorBeginTouchEvent] {
464 raw_event_slice(raw.beginEvents, raw.beginCount)
465}
466
467fn sensor_end_slice<'a>(raw: ffi::b3SensorEvents) -> &'a [ffi::b3SensorEndTouchEvent] {
468 raw_event_slice(raw.endEvents, raw.endCount)
469}
470
471fn contact_begin_slice<'a>(raw: ffi::b3ContactEvents) -> &'a [ffi::b3ContactBeginTouchEvent] {
472 raw_event_slice(raw.beginEvents, raw.beginCount)
473}
474
475fn contact_end_slice<'a>(raw: ffi::b3ContactEvents) -> &'a [ffi::b3ContactEndTouchEvent] {
476 raw_event_slice(raw.endEvents, raw.endCount)
477}
478
479fn contact_hit_slice<'a>(raw: ffi::b3ContactEvents) -> &'a [ffi::b3ContactHitEvent] {
480 raw_event_slice(raw.hitEvents, raw.hitCount)
481}
482
483fn joint_event_slice<'a>(raw: ffi::b3JointEvents) -> &'a [ffi::b3JointEvent] {
484 raw_event_slice(raw.jointEvents, raw.count)
485}
486
487impl World {
488 pub fn body_events(&self) -> Vec<BodyMoveEvent> {
494 self.try_body_events().expect("invalid Box3D world")
495 }
496
497 pub fn try_body_events(&self) -> Result<Vec<BodyMoveEvent>> {
502 let mut out = Vec::new();
503 self.try_body_events_into(&mut out)?;
504 Ok(out)
505 }
506
507 pub fn body_events_into(&self, out: &mut Vec<BodyMoveEvent>) {
512 self.try_body_events_into(out).expect("invalid Box3D world");
513 }
514
515 pub fn try_body_events_into(&self, out: &mut Vec<BodyMoveEvent>) -> Result<()> {
517 callback_state::check_not_in_callback()?;
518 let _guard = box3d_lock::lock();
519 self.check_world_valid_locked()?;
520 let raw = unsafe { ffi::b3World_GetBodyEvents(self.raw()) };
521 let events = body_event_slice(raw);
522 map_snapshot_into(out, events, |event| BodyMoveEvent {
523 body_id: BodyId::from_raw(event.bodyId),
524 transform: WorldTransform::from_raw(event.transform),
525 fell_asleep: event.fellAsleep,
526 raw_user_data: event.userData,
527 });
528 Ok(())
529 }
530
531 pub fn try_with_body_events_view<T>(&self, f: impl FnOnce(BodyMoveIter<'_>) -> T) -> Result<T> {
545 callback_state::check_not_in_callback()?;
546 let _guard = box3d_lock::lock();
547 self.check_world_valid_locked()?;
548 let raw = unsafe { ffi::b3World_GetBodyEvents(self.raw()) };
549 let events = body_event_slice(raw);
550 drop(_guard);
551 Ok(f(BodyMoveIter(events.iter())))
552 }
553
554 pub fn with_body_events_view<T>(&self, f: impl FnOnce(BodyMoveIter<'_>) -> T) -> T {
559 self.try_with_body_events_view(f)
560 .expect("invalid Box3D world")
561 }
562
563 pub unsafe fn try_with_body_events_raw<T>(
573 &self,
574 f: impl FnOnce(&[ffi::b3BodyMoveEvent]) -> T,
575 ) -> Result<T> {
576 callback_state::check_not_in_callback()?;
577 let _guard = box3d_lock::lock();
578 self.check_world_valid_locked()?;
579 let raw = unsafe { ffi::b3World_GetBodyEvents(self.raw()) };
580 let events = body_event_slice(raw);
581 drop(_guard);
582 Ok(f(events))
583 }
584
585 pub unsafe fn with_body_events_raw<T>(
591 &self,
592 f: impl FnOnce(&[ffi::b3BodyMoveEvent]) -> T,
593 ) -> T {
594 unsafe { self.try_with_body_events_raw(f) }.expect("invalid Box3D world")
595 }
596
597 pub fn sensor_events(&self) -> SensorEvents {
603 self.try_sensor_events().expect("invalid Box3D world")
604 }
605
606 pub fn try_sensor_events(&self) -> Result<SensorEvents> {
608 let mut out = SensorEvents::default();
609 self.try_sensor_events_into(&mut out)?;
610 Ok(out)
611 }
612
613 pub fn sensor_events_into(&self, out: &mut SensorEvents) {
615 self.try_sensor_events_into(out)
616 .expect("invalid Box3D world");
617 }
618
619 pub fn try_sensor_events_into(&self, out: &mut SensorEvents) -> Result<()> {
621 callback_state::check_not_in_callback()?;
622 let _guard = box3d_lock::lock();
623 self.check_world_valid_locked()?;
624 let raw = unsafe { ffi::b3World_GetSensorEvents(self.raw()) };
625 map_snapshot_into(&mut out.begin, sensor_begin_slice(raw), |event| {
626 SensorBeginTouchEvent {
627 sensor_shape: ShapeId::from_raw(event.sensorShapeId),
628 visitor_shape: ShapeId::from_raw(event.visitorShapeId),
629 }
630 });
631 map_snapshot_into(&mut out.end, sensor_end_slice(raw), |event| {
632 SensorEndTouchEvent {
633 sensor_shape: ShapeId::from_raw(event.sensorShapeId),
634 visitor_shape: ShapeId::from_raw(event.visitorShapeId),
635 }
636 });
637 Ok(())
638 }
639
640 pub fn try_with_sensor_events_view<T>(
654 &self,
655 f: impl FnOnce(SensorBeginIter<'_>, SensorEndIter<'_>) -> T,
656 ) -> Result<T> {
657 callback_state::check_not_in_callback()?;
658 let _guard = box3d_lock::lock();
659 self.check_world_valid_locked()?;
660 let raw = unsafe { ffi::b3World_GetSensorEvents(self.raw()) };
661 let begin = sensor_begin_slice(raw);
662 let end = sensor_end_slice(raw);
663 drop(_guard);
664 Ok(f(SensorBeginIter(begin.iter()), SensorEndIter(end.iter())))
665 }
666
667 pub fn with_sensor_events_view<T>(
672 &self,
673 f: impl FnOnce(SensorBeginIter<'_>, SensorEndIter<'_>) -> T,
674 ) -> T {
675 self.try_with_sensor_events_view(f)
676 .expect("invalid Box3D world")
677 }
678
679 pub unsafe fn try_with_sensor_events_raw<T>(
687 &self,
688 f: impl FnOnce(&[ffi::b3SensorBeginTouchEvent], &[ffi::b3SensorEndTouchEvent]) -> T,
689 ) -> Result<T> {
690 callback_state::check_not_in_callback()?;
691 let _guard = box3d_lock::lock();
692 self.check_world_valid_locked()?;
693 let raw = unsafe { ffi::b3World_GetSensorEvents(self.raw()) };
694 let begin = sensor_begin_slice(raw);
695 let end = sensor_end_slice(raw);
696 drop(_guard);
697 Ok(f(begin, end))
698 }
699
700 pub unsafe fn with_sensor_events_raw<T>(
706 &self,
707 f: impl FnOnce(&[ffi::b3SensorBeginTouchEvent], &[ffi::b3SensorEndTouchEvent]) -> T,
708 ) -> T {
709 unsafe { self.try_with_sensor_events_raw(f) }.expect("invalid Box3D world")
710 }
711
712 pub fn contact_events(&self) -> ContactEvents {
717 self.try_contact_events().expect("invalid Box3D world")
718 }
719
720 pub fn try_contact_events(&self) -> Result<ContactEvents> {
722 let mut out = ContactEvents::default();
723 self.try_contact_events_into(&mut out)?;
724 Ok(out)
725 }
726
727 pub fn contact_events_into(&self, out: &mut ContactEvents) {
729 self.try_contact_events_into(out)
730 .expect("invalid Box3D world");
731 }
732
733 pub fn contact_data(&self, contact_id: ContactId) -> ContactData {
739 self.try_contact_data(contact_id)
740 .expect("invalid ContactId or Box3D world")
741 }
742
743 pub fn try_contact_data(&self, contact_id: ContactId) -> Result<ContactData> {
747 callback_state::check_not_in_callback()?;
748 let _guard = box3d_lock::lock();
749 self.check_contact_belongs_locked(contact_id)?;
750 let raw = unsafe { ffi::b3Contact_GetData(contact_id.into_raw()) };
751 Ok(unsafe { ContactData::from_raw(raw) })
752 }
753
754 pub fn try_contact_events_into(&self, out: &mut ContactEvents) -> Result<()> {
756 callback_state::check_not_in_callback()?;
757 let _guard = box3d_lock::lock();
758 self.check_world_valid_locked()?;
759 let raw = unsafe { ffi::b3World_GetContactEvents(self.raw()) };
760 map_snapshot_into(&mut out.begin, contact_begin_slice(raw), |event| {
761 ContactBeginTouchEvent {
762 shape_a: ShapeId::from_raw(event.shapeIdA),
763 shape_b: ShapeId::from_raw(event.shapeIdB),
764 contact_id: ContactId::from_raw(event.contactId),
765 }
766 });
767 map_snapshot_into(&mut out.end, contact_end_slice(raw), |event| {
768 ContactEndTouchEvent {
769 shape_a: ShapeId::from_raw(event.shapeIdA),
770 shape_b: ShapeId::from_raw(event.shapeIdB),
771 contact_id: ContactId::from_raw(event.contactId),
772 }
773 });
774 map_snapshot_into(&mut out.hit, contact_hit_slice(raw), |event| {
775 ContactHitEvent {
776 shape_a: ShapeId::from_raw(event.shapeIdA),
777 shape_b: ShapeId::from_raw(event.shapeIdB),
778 contact_id: ContactId::from_raw(event.contactId),
779 point: Pos::from_raw(event.point),
780 normal: Vec3::from_raw(event.normal),
781 approach_speed: event.approachSpeed,
782 user_material_id_a: event.userMaterialIdA,
783 user_material_id_b: event.userMaterialIdB,
784 }
785 });
786 Ok(())
787 }
788
789 pub fn try_with_contact_events_view<T>(
803 &self,
804 f: impl FnOnce(ContactBeginIter<'_>, ContactEndIter<'_>, ContactHitIter<'_>) -> T,
805 ) -> Result<T> {
806 callback_state::check_not_in_callback()?;
807 let _guard = box3d_lock::lock();
808 self.check_world_valid_locked()?;
809 let raw = unsafe { ffi::b3World_GetContactEvents(self.raw()) };
810 let begin = contact_begin_slice(raw);
811 let end = contact_end_slice(raw);
812 let hit = contact_hit_slice(raw);
813 drop(_guard);
814 Ok(f(
815 ContactBeginIter(begin.iter()),
816 ContactEndIter(end.iter()),
817 ContactHitIter(hit.iter()),
818 ))
819 }
820
821 pub fn with_contact_events_view<T>(
826 &self,
827 f: impl FnOnce(ContactBeginIter<'_>, ContactEndIter<'_>, ContactHitIter<'_>) -> T,
828 ) -> T {
829 self.try_with_contact_events_view(f)
830 .expect("invalid Box3D world")
831 }
832
833 pub unsafe fn try_with_contact_events_raw<T>(
841 &self,
842 f: impl FnOnce(
843 &[ffi::b3ContactBeginTouchEvent],
844 &[ffi::b3ContactEndTouchEvent],
845 &[ffi::b3ContactHitEvent],
846 ) -> T,
847 ) -> Result<T> {
848 callback_state::check_not_in_callback()?;
849 let _guard = box3d_lock::lock();
850 self.check_world_valid_locked()?;
851 let raw = unsafe { ffi::b3World_GetContactEvents(self.raw()) };
852 let begin = contact_begin_slice(raw);
853 let end = contact_end_slice(raw);
854 let hit = contact_hit_slice(raw);
855 drop(_guard);
856 Ok(f(begin, end, hit))
857 }
858
859 pub unsafe fn with_contact_events_raw<T>(
865 &self,
866 f: impl FnOnce(
867 &[ffi::b3ContactBeginTouchEvent],
868 &[ffi::b3ContactEndTouchEvent],
869 &[ffi::b3ContactHitEvent],
870 ) -> T,
871 ) -> T {
872 unsafe { self.try_with_contact_events_raw(f) }.expect("invalid Box3D world")
873 }
874
875 pub fn joint_events(&self) -> Vec<JointEvent> {
881 self.try_joint_events().expect("invalid Box3D world")
882 }
883
884 pub fn try_joint_events(&self) -> Result<Vec<JointEvent>> {
886 let mut out = Vec::new();
887 self.try_joint_events_into(&mut out)?;
888 Ok(out)
889 }
890
891 pub fn joint_events_into(&self, out: &mut Vec<JointEvent>) {
893 self.try_joint_events_into(out)
894 .expect("invalid Box3D world");
895 }
896
897 pub fn try_joint_events_into(&self, out: &mut Vec<JointEvent>) -> Result<()> {
899 callback_state::check_not_in_callback()?;
900 let _guard = box3d_lock::lock();
901 self.check_world_valid_locked()?;
902 let raw = unsafe { ffi::b3World_GetJointEvents(self.raw()) };
903 map_snapshot_into(out, joint_event_slice(raw), |event| JointEvent {
904 joint_id: JointId::from_raw(event.jointId),
905 raw_user_data: event.userData,
906 });
907 Ok(())
908 }
909
910 pub fn try_with_joint_events_view<T>(
923 &self,
924 f: impl FnOnce(JointEventIter<'_>) -> T,
925 ) -> Result<T> {
926 callback_state::check_not_in_callback()?;
927 let _guard = box3d_lock::lock();
928 self.check_world_valid_locked()?;
929 let raw = unsafe { ffi::b3World_GetJointEvents(self.raw()) };
930 let events = joint_event_slice(raw);
931 drop(_guard);
932 Ok(f(JointEventIter(events.iter())))
933 }
934
935 pub fn with_joint_events_view<T>(&self, f: impl FnOnce(JointEventIter<'_>) -> T) -> T {
940 self.try_with_joint_events_view(f)
941 .expect("invalid Box3D world")
942 }
943
944 pub unsafe fn try_with_joint_events_raw<T>(
952 &self,
953 f: impl FnOnce(&[ffi::b3JointEvent]) -> T,
954 ) -> Result<T> {
955 callback_state::check_not_in_callback()?;
956 let _guard = box3d_lock::lock();
957 self.check_world_valid_locked()?;
958 let raw = unsafe { ffi::b3World_GetJointEvents(self.raw()) };
959 let events = joint_event_slice(raw);
960 drop(_guard);
961 Ok(f(events))
962 }
963
964 pub unsafe fn with_joint_events_raw<T>(&self, f: impl FnOnce(&[ffi::b3JointEvent]) -> T) -> T {
970 unsafe { self.try_with_joint_events_raw(f) }.expect("invalid Box3D world")
971 }
972}