Something went wrong. Try again.
we (web engine): Experimental web browser project to understand the limits of Claude
Something went wrong. Try again.
Rust
at url-parser
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286//! Minimal CoreFoundation bindings.//!//! Provides `CFStringRef` creation from Rust strings and RAII reference//! counting via [`CfString`]. These bindings are needed for passing string//! parameters to AppKit APIs (window titles, menu items, etc).//!//! # Safety//!//! This module contains `unsafe` code for FFI with CoreFoundation.//! The `platform` crate is one of the few crates where `unsafe` is permitted.
use std::fmt;use std::os::raw::c_void;use std::ptr::NonNull;
// ---------------------------------------------------------------------------// Raw FFI types// ---------------------------------------------------------------------------
/// Opaque CoreFoundation string type.#[repr(C)]pub struct __CFString { _private: [u8; 0],}
/// A reference to a CoreFoundation string (immutable).pub type CFStringRef = *const __CFString;
/// CoreFoundation index/size type.pub type CFIndex = isize;
/// CoreFoundation string encoding identifier.pub type CFStringEncoding = u32;
/// CoreFoundation Boolean type.pub type CFBoolean = u8;
/// UTF-8 encoding constant.pub const K_CF_STRING_ENCODING_UTF8: CFStringEncoding = 0x0800_0100;
// ---------------------------------------------------------------------------// Raw FFI bindings to CoreFoundation.framework// ---------------------------------------------------------------------------
#[link(name = "CoreFoundation", kind = "framework")]extern "C" { fn CFStringCreateWithBytes( alloc: *const c_void, bytes: *const u8, num_bytes: CFIndex, encoding: CFStringEncoding, is_external_representation: CFBoolean, ) -> CFStringRef;
fn CFRetain(cf: *const c_void) -> *const c_void; fn CFRelease(cf: *const c_void);
fn CFStringGetLength(string: CFStringRef) -> CFIndex; fn CFStringGetCString( string: CFStringRef, buffer: *mut u8, buffer_size: CFIndex, encoding: CFStringEncoding, ) -> CFBoolean;}
// ---------------------------------------------------------------------------// Public wrappers for CFRetain / CFRelease// ---------------------------------------------------------------------------
/// Increment the reference count of a CoreFoundation object.////// # Safety////// `ptr` must point to a valid CoreFoundation object.#[inline]pub unsafe fn cf_retain(ptr: *const c_void) -> *const c_void { CFRetain(ptr)}
/// Decrement the reference count of a CoreFoundation object.////// # Safety////// `ptr` must point to a valid CoreFoundation object with a positive/// reference count. The object may be deallocated after this call.#[inline]pub unsafe fn cf_release(ptr: *const c_void) { CFRelease(ptr);}
// ---------------------------------------------------------------------------// CfString — RAII wrapper around CFStringRef// ---------------------------------------------------------------------------
/// An owned CoreFoundation string that calls `CFRelease` on drop.////// Created from a Rust `&str` via [`CfString::new`]. The underlying/// `CFStringRef` can be borrowed with [`CfString::as_cf_ref`] for passing/// to AppKit APIs.pub struct CfString(NonNull<__CFString>);
impl CfString { /// Create a `CfString` from a Rust string slice. /// /// Returns `None` if CoreFoundation fails to create the string (should /// only happen for extremely large strings or out-of-memory conditions). pub fn new(s: &str) -> Option<CfString> { let ptr = unsafe { CFStringCreateWithBytes( std::ptr::null(), // default allocator s.as_ptr(), s.len() as CFIndex, K_CF_STRING_ENCODING_UTF8, 0, // not external representation ) }; // CFStringCreateWithBytes returns null on failure. NonNull::new(ptr as *mut __CFString).map(CfString) }
/// Return the raw `CFStringRef` for passing to CoreFoundation / AppKit APIs. #[inline] pub fn as_cf_ref(&self) -> CFStringRef { self.0.as_ptr() as CFStringRef }
/// Return the raw pointer as `*const c_void` for APIs that take a generic /// CoreFoundation type reference. #[inline] pub fn as_void_ptr(&self) -> *const c_void { self.0.as_ptr() as *const c_void }
/// Get the length of the string in UTF-16 code units. pub fn len(&self) -> usize { let len = unsafe { CFStringGetLength(self.as_cf_ref()) }; len as usize }
/// Returns `true` if the string is empty. pub fn is_empty(&self) -> bool { self.len() == 0 }
/// Try to extract the string contents as a Rust `String`. /// /// This is primarily useful for testing and debugging. pub fn to_string_lossy(&self) -> String { // Allocate a buffer large enough for the UTF-8 representation. // CFStringGetCString needs space for a NUL terminator. // Worst case: each UTF-16 code unit -> 3 UTF-8 bytes + NUL. let max_len = self.len() * 3 + 1; let mut buf = vec![0u8; max_len];
let ok = unsafe { CFStringGetCString( self.as_cf_ref(), buf.as_mut_ptr(), buf.len() as CFIndex, K_CF_STRING_ENCODING_UTF8, ) };
if ok != 0 { // Find the NUL terminator. let nul_pos = buf.iter().position(|&b| b == 0).unwrap_or(buf.len()); String::from_utf8_lossy(&buf[..nul_pos]).into_owned() } else { String::new() } }}
impl Clone for CfString { fn clone(&self) -> CfString { unsafe { cf_retain(self.as_void_ptr()) }; CfString(self.0) }}
impl Drop for CfString { fn drop(&mut self) { unsafe { cf_release(self.as_void_ptr()) }; }}
impl fmt::Debug for CfString { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "CfString(\"{}\")", self.to_string_lossy()) }}
impl fmt::Display for CfString { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.to_string_lossy()) }}
// SAFETY: CFString is an immutable, reference-counted CoreFoundation type.// CFRetain/CFRelease are thread-safe.unsafe impl Send for CfString {}unsafe impl Sync for CfString {}
// ---------------------------------------------------------------------------// Tests// ---------------------------------------------------------------------------
#[cfg(test)]mod tests { use super::*;
#[test] fn create_cfstring_from_str() { let s = CfString::new("Hello, world!").expect("should create CFString"); assert_eq!(s.to_string_lossy(), "Hello, world!"); }
#[test] fn cfstring_length() { let s = CfString::new("abc").expect("should create CFString"); assert_eq!(s.len(), 3); }
#[test] fn cfstring_empty() { let s = CfString::new("").expect("should create empty CFString"); assert!(s.is_empty()); assert_eq!(s.len(), 0); assert_eq!(s.to_string_lossy(), ""); }
#[test] fn cfstring_unicode() { let s = CfString::new("caf\u{00e9}").expect("should handle unicode"); assert_eq!(s.to_string_lossy(), "caf\u{00e9}"); // "caf\u{e9}" is 4 UTF-16 code units assert_eq!(s.len(), 4); }
#[test] fn cfstring_emoji() { // Emoji outside BMP: encoded as surrogate pair in UTF-16 (2 code units) let s = CfString::new("\u{1F600}").expect("should handle emoji"); assert_eq!(s.to_string_lossy(), "\u{1F600}"); assert_eq!(s.len(), 2); // surrogate pair }
#[test] fn cfstring_clone_and_drop() { let s = CfString::new("test clone").expect("should create"); let s2 = s.clone(); assert_eq!(s.to_string_lossy(), s2.to_string_lossy()); // Both should be droppable without crash (refcount was incremented). drop(s); assert_eq!(s2.to_string_lossy(), "test clone"); }
#[test] fn cfstring_debug_format() { let s = CfString::new("debug").expect("should create"); let debug = format!("{:?}", s); assert!(debug.contains("CfString")); assert!(debug.contains("debug")); }
#[test] fn cfstring_display_format() { let s = CfString::new("display").expect("should create"); let display = format!("{}", s); assert_eq!(display, "display"); }
#[test] fn cfstring_as_cf_ref_not_null() { let s = CfString::new("ptr test").expect("should create"); assert!(!s.as_cf_ref().is_null()); }
#[test] fn cfstring_as_void_ptr_not_null() { let s = CfString::new("void test").expect("should create"); assert!(!s.as_void_ptr().is_null()); }}