makepad/libs/relax/compiler/tests/n01_fnptr_debug_hr.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

107 lines
3.5 KiB
Rust

// Higher-ranked fn pointers implement Debug and Pointer (real core:
// library/core/src/ptr/mod.rs `impl<F: FnPtr> fmt::Debug for F`), so a
// `&for<'a> fn(&'a mut T)` unsize-coerces to `&dyn Debug` as #[derive(Debug)]
// needs for fields holding such pointers or Options/tuples/slices of them.
use std::any::Any;
use std::fmt::{self, Debug};
use std::sync::Arc;
struct Registry {
count: u32,
}
type Register = fn(&mut Registry, Option<u32>) -> Result<u32, String>;
type Leaf = fn(&mut Registry) -> Result<u32, String>;
#[derive(Clone, Copy, Debug)]
enum FieldType {
Builtin(&'static str),
Registered(Register),
}
#[derive(Clone, Default, Debug)]
struct Vars {
lookup: Option<fn(&dyn Any) -> Option<u32>>,
write: Option<fn(&mut dyn Any, &dyn Any) -> bool>,
leaf: Option<Leaf>,
pair: Option<(Leaf, u8)>,
chain: Option<Arc<[Register]>>,
styles: Option<fn(&mut Registry)>,
}
fn register(registry: &mut Registry, extra: Option<u32>) -> Result<u32, String> {
registry.count += extra.unwrap_or(1);
Ok(registry.count)
}
fn leaf(registry: &mut Registry) -> Result<u32, String> {
Ok(registry.count)
}
fn lookup(_value: &dyn Any) -> Option<u32> {
None
}
fn bump(registry: &mut Registry) {
registry.count += 1;
}
fn shown<T: Debug + ?Sized>(value: &T) -> String {
format!("{:?}", value)
}
fn pointed<T: fmt::Pointer>(value: T) -> String {
format!("{:p}", value)
}
#[test]
fn higher_ranked_fn_pointers_are_debug() {
let address = format!("{:p}", register as Register as *const ());
let registered = FieldType::Registered(register);
assert_eq!(format!("{:?}", registered), format!("Registered({})", address));
assert_eq!(format!("{:?}", FieldType::Builtin("f32")), "Builtin(\"f32\")");
let pointer: Register = register;
assert_eq!(format!("{:?}", pointer), address);
assert_eq!(format!("{:p}", pointer), address);
let dynamic: &dyn Debug = &pointer;
assert_eq!(format!("{:?}", dynamic), address);
assert_eq!(pointed(pointer), address);
assert_eq!(shown(&pointer), address);
let explicit: for<'a> fn(&'a mut Registry) -> Result<u32, String> = leaf;
let leaf_address = format!("{:p}", explicit as *const ());
assert_eq!(shown(&explicit), leaf_address);
let vars = Vars {
lookup: Some(lookup),
leaf: Some(leaf),
pair: Some((leaf, 7)),
chain: Some(Arc::from(vec![pointer, pointer])),
styles: Some(bump),
..Vars::default()
};
let text = format!("{:?}", vars);
assert!(text.starts_with("Vars { lookup: Some(0x"), "{}", text);
assert!(text.contains("write: None"), "{}", text);
assert!(text.contains(&format!("leaf: Some({})", leaf_address)), "{}", text);
assert!(text.contains(&format!("pair: Some(({}, 7))", leaf_address)), "{}", text);
assert!(text.contains(&format!("chain: Some([{}, {}])", address, address)), "{}", text);
assert!(vars.lookup.is_some_and(|f| f(&1u8).is_none()));
assert!(vars.write.is_none());
assert_eq!(vars.pair.map(|(_, n)| n), Some(7));
assert_eq!(vars.chain.as_ref().map(|c| c.len()), Some(2));
if let FieldType::Registered(f) = registered {
assert!(std::ptr::fn_addr_eq(f, pointer));
}
if let FieldType::Builtin(name) = FieldType::Builtin("f32") {
assert_eq!(name, "f32");
}
let mut registry = Registry { count: 1 };
assert_eq!(pointer(&mut registry, Some(2)), Ok(3));
(vars.styles.unwrap())(&mut registry);
assert_eq!((vars.leaf.unwrap())(&mut registry), Ok(4));
assert!(std::ptr::fn_addr_eq(pointer, register as Register));
}