makepad/libs/relax/compiler/tests/niche.rs
Admin b22a714840 makepad run: the Rust JIT (libs/relax) and makepad-remote
The JIT that runs makepad apps from source: lexer, front end, type checker,
lazy borrow checker (Gandalf; `--check-first` opts in), codegen, session and
warm/cold caches keyed by compiler stamp, provided crates bound late,
startup images, live patching. User-facing name is `makepad run` (binary
`makepad`, MAKEPAD_RUN_* env, ~/.makepad-run); libs/relax stays the internal
library name. `makepad check` reports rustc-style diagnostics with rustc
error codes and checks a whole workspace (`--workspace`). Runs on macOS,
Linux, Windows and Android. makepad-remote: one tool schema for apps and the
WM (app/1): grabs, captures, traces, frame profiles and tweaks.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-13 12:26:21 +02:00

54 lines
2.3 KiB
Rust

// null-pointer niche layouts (rustc guarantees them for Option<&T> / Option<&mut T> /
// Option<NonNull<T>> / Option<fn()>; Box/Rc/Arc/Vec get it once std stores NonNull): same size as the pointer, None is
// null, and C receives Option<extern "C" fn> as a nullable function pointer
use std::ptr::NonNull;
extern "C" {
fn qsort(base: *mut u8, n: usize, w: usize, cmp: Option<extern "C" fn(*const u8, *const u8) -> i32>);
}
extern "C" fn cmp_u8(a: *const u8, b: *const u8) -> i32 { unsafe { *a as i32 - *b as i32 } }
#[derive(Debug, PartialEq, Clone)]
enum E<'a> { Empty, Has(u32, &'a str) }
#[test]
fn niche_layouts() {
assert_eq!(std::mem::size_of::<Option<&u32>>(), 8);
assert_eq!(std::mem::size_of::<Option<NonNull<u8>>>(), 8);
assert_eq!(std::mem::size_of::<Option<fn()>>(), 8);
assert_eq!(std::mem::size_of::<Option<&str>>(), 16);
let x = 5u32;
let a: Option<&u32> = Some(&x);
let n: Option<&u32> = None;
assert_eq!(unsafe { std::mem::transmute::<Option<&u32>, usize>(n) }, 0);
assert_eq!(a.copied(), Some(5));
assert!(n.is_none());
let b: Option<Box<String>> = Some(Box::new("hi".into()));
match &b { Some(s) => assert_eq!(s.len(), 2), None => panic!() }
let v: Vec<Option<Box<u32>>> = vec![None, Some(Box::new(3)), None];
assert_eq!(v.iter().filter(|x| x.is_some()).count(), 1);
let e = E::Has(1, "a");
assert_eq!(e.clone(), E::Has(1, "a"));
assert_ne!(E::Empty, e);
let mut arr = [3u8, 1, 2];
unsafe { qsort(arr.as_mut_ptr(), 3, 1, Some(cmp_u8)) };
assert_eq!(arr, [1, 2, 3]);
let f: Option<fn(u32) -> u32> = Some(|x| x + 1);
assert_eq!(f.map(|g| g(1)), Some(2));
let s: Option<Vec<u32>> = Some(vec![1]);
if let Some(ref v) = s { assert_eq!(v[0], 1); }
}
// a closure's by-reference captures are references (never null): Option<closure> uses one as
// its niche (rustc's `&T` / `&mut T` upvars; Relax typed them `*mut T`, 16 bytes)
#[test]
fn closure_capture_niche() {
use std::mem::size_of_val;
let a = 10i32;
let mut m = 0u8;
let b = Some(|| a + 1);
let mut c = Some(|| { m += 1; m });
let a4 = 14i32;
let e = Some(move || a4);
assert_eq!((size_of_val(&b), size_of_val(&e)), (8, 8));
assert_eq!(size_of_val(&c), 8);
assert_eq!(c.as_mut().unwrap()(), 1);
assert_eq!(b.unwrap()() + e.unwrap()(), 25);
}