From d7cf3efc9670d6a66831dcdd3901892b324154e4 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 15 Apr 2026 14:51:16 +0100 Subject: [PATCH 1/4] Allow casting between nullptr's of different types --- libcc2rs/src/rc.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libcc2rs/src/rc.rs b/libcc2rs/src/rc.rs index eb197ee2..e467ed59 100644 --- a/libcc2rs/src/rc.rs +++ b/libcc2rs/src/rc.rs @@ -1077,7 +1077,7 @@ pub struct AnyPtr { ptr: Rc, } -impl Ptr { +impl Ptr { pub fn to_any(&self) -> AnyPtr { AnyPtr { ptr: Rc::new(self.clone()), @@ -1093,6 +1093,11 @@ impl Default for AnyPtr { impl AnyPtr { pub fn cast(&self) -> Option> { + if let Some(p) = self.ptr.as_any().downcast_ref::>() { + if p.is_null() { + return Some(Ptr::::null()); + } + } self.ptr.as_any().downcast_ref::>().cloned() } From d9e6c57bee76b5f1a560f7e186cbc82785ac714b Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 15 Apr 2026 14:51:01 +0100 Subject: [PATCH 2/4] Drop Clone trait from ErasedPtr --- libcc2rs/src/rc.rs | 30 ++++-------------------------- 1 file changed, 4 insertions(+), 26 deletions(-) diff --git a/libcc2rs/src/rc.rs b/libcc2rs/src/rc.rs index e467ed59..ef80560c 100644 --- a/libcc2rs/src/rc.rs +++ b/libcc2rs/src/rc.rs @@ -1013,7 +1013,7 @@ trait ErasedPtr: std::any::Any { impl ErasedPtr for Ptr where - T: Clone + ByteRepr + 'static, + T: ByteRepr + 'static, Ptr: PartialEq, { fn pointee_type_id(&self) -> std::any::TypeId { @@ -1024,35 +1024,13 @@ where if self.pointee_type_id() != src.pointee_type_id() { panic!("memcpy: type mismatch"); } - let src_ptr = src .as_any() .downcast_ref::>() .expect("memcpy: downcast to Ptr failed"); - - let elem = std::mem::size_of::(); - - if len == elem { - self.write(src_ptr.read()); - return; - } - - if elem != 0 && len.is_multiple_of(elem) { - let mut dst = self.clone(); - let mut src_it = src_ptr.clone(); - for _ in 0..(len / elem) { - dst.write(src_it.read()); - dst += 1; - src_it += 1; - } - - return; - } - - panic!( - "memcpy: len {} not compatible with element size {}", - len, elem - ); + let dst_bytes: Ptr = self.reinterpret_cast(); + let src_bytes: Ptr = src_ptr.reinterpret_cast(); + dst_bytes.memcpy(&src_bytes, len); } fn as_any(&self) -> &dyn std::any::Any { From 6209876e376dea6bcd379531a719a44599f80eb7 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Thu, 16 Apr 2026 18:45:57 +0100 Subject: [PATCH 3/4] Add tests --- libcc2rs/src/rc.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/libcc2rs/src/rc.rs b/libcc2rs/src/rc.rs index ef80560c..741c0419 100644 --- a/libcc2rs/src/rc.rs +++ b/libcc2rs/src/rc.rs @@ -1269,4 +1269,25 @@ mod tests { p.delete(); } + + #[test] + fn anyptr_null_cast() { + let any = Ptr::<()>::null().to_any(); + let p: Option> = any.cast::(); + assert!(p.is_some()); + assert!(p.unwrap().is_null()); + + let p2: Option> = any.cast::(); + assert!(p2.is_some()); + assert!(p2.unwrap().is_null()); + } + + #[test] + fn to_any_without_clone() { + let p: Ptr = Ptr::null(); // std::fs::File is not Clone + let any = p.to_any(); + let recovered = any.cast::(); + assert!(recovered.is_some()); + assert!(recovered.unwrap().is_null()); + } } From b21bdf104290dbc8cc0006dc71b7ce21d8505ed6 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Thu, 16 Apr 2026 18:53:52 +0100 Subject: [PATCH 4/4] Allow nullptr conversions between any ptr types --- libcc2rs/src/rc.rs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/libcc2rs/src/rc.rs b/libcc2rs/src/rc.rs index 741c0419..e02e9626 100644 --- a/libcc2rs/src/rc.rs +++ b/libcc2rs/src/rc.rs @@ -1009,6 +1009,7 @@ trait ErasedPtr: std::any::Any { fn memcpy(&self, src: &dyn ErasedPtr, len: usize); fn as_any(&self) -> &dyn std::any::Any; fn equals(&self, other: &dyn ErasedPtr) -> Option; + fn is_null(&self) -> bool; } impl ErasedPtr for Ptr @@ -1048,6 +1049,10 @@ where None } + + fn is_null(&self) -> bool { + Ptr::is_null(self) + } } #[derive(Clone)] @@ -1071,10 +1076,8 @@ impl Default for AnyPtr { impl AnyPtr { pub fn cast(&self) -> Option> { - if let Some(p) = self.ptr.as_any().downcast_ref::>() { - if p.is_null() { - return Some(Ptr::::null()); - } + if self.ptr.is_null() { + return Some(Ptr::::null()); } self.ptr.as_any().downcast_ref::>().cloned() } @@ -1272,6 +1275,7 @@ mod tests { #[test] fn anyptr_null_cast() { + // void* nullptr let any = Ptr::<()>::null().to_any(); let p: Option> = any.cast::(); assert!(p.is_some()); @@ -1280,6 +1284,12 @@ mod tests { let p2: Option> = any.cast::(); assert!(p2.is_some()); assert!(p2.unwrap().is_null()); + + // int* nullptr + let any2 = Ptr::::null().to_any(); + let p3: Option> = any2.cast::(); + assert!(p3.is_some()); + assert!(p3.unwrap().is_null()); } #[test]