1use std::ffi::{c_char, c_void};
22use std::ptr::NonNull;
23
24use mtl_sys::{class, msg_send_0, msg_send_1, sel};
25
26use crate::object::{Copying, Referencing};
27use crate::string::String;
28
29#[repr(transparent)]
33#[derive(Clone)]
34pub struct Url(NonNull<c_void>);
35
36impl Url {
37 #[inline]
41 pub fn file_url_with_path(path: &String) -> Option<Self> {
42 unsafe {
43 let ptr: *mut c_void = msg_send_1(
44 class!(NSURL).as_ptr(),
45 sel!(fileURLWithPath:),
46 path.as_ptr(),
47 );
48 Self::from_ptr(ptr)
49 }
50 }
51
52 #[inline]
56 pub fn alloc() -> Option<Self> {
57 unsafe {
58 let ptr: *mut c_void = msg_send_0(class!(NSURL).as_ptr(), sel!(alloc));
59 Self::from_ptr(ptr)
60 }
61 }
62
63 #[inline]
67 pub fn init(&self) -> Option<Self> {
68 unsafe {
69 let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(init));
70 Self::from_ptr(ptr)
71 }
72 }
73
74 #[inline]
78 pub fn init_with_string(&self, string: &String) -> Option<Self> {
79 unsafe {
80 let ptr: *mut c_void =
81 msg_send_1(self.as_ptr(), sel!(initWithString:), string.as_ptr());
82 Self::from_ptr(ptr)
83 }
84 }
85
86 #[inline]
90 pub fn init_file_url_with_path(&self, path: &String) -> Option<Self> {
91 unsafe {
92 let ptr: *mut c_void =
93 msg_send_1(self.as_ptr(), sel!(initFileURLWithPath:), path.as_ptr());
94 Self::from_ptr(ptr)
95 }
96 }
97
98 #[inline]
102 pub fn file_system_representation(&self) -> *const c_char {
103 unsafe { msg_send_0(self.as_ptr(), sel!(fileSystemRepresentation)) }
104 }
105
106 #[inline]
112 pub unsafe fn from_ptr(ptr: *mut c_void) -> Option<Self> {
113 NonNull::new(ptr).map(Self)
114 }
115
116 #[inline]
122 pub fn from_path(path: &std::path::Path) -> Option<Self> {
123 let path_str = path.to_str()?;
124 let ns_string = String::from_str(path_str)?;
125 Self::file_url_with_path(&ns_string)
126 }
127}
128
129impl Referencing for Url {
130 #[inline]
131 fn as_ptr(&self) -> *const c_void {
132 self.0.as_ptr()
133 }
134}
135
136impl Copying for Url {
137 #[inline]
138 fn copy(&self) -> Option<Self> {
139 unsafe {
140 let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(copy));
141 Self::from_ptr(ptr)
142 }
143 }
144}
145
146unsafe impl Send for Url {}
148unsafe impl Sync for Url {}
149
150impl std::fmt::Debug for Url {
151 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
152 let repr = self.file_system_representation();
153 if repr.is_null() {
154 f.debug_struct("Url").field("ptr", &self.0).finish()
155 } else {
156 let s = unsafe { std::ffi::CStr::from_ptr(repr) };
157 f.debug_struct("Url")
158 .field("path", &s.to_string_lossy())
159 .finish()
160 }
161 }
162}
163
164#[cfg(test)]
165mod tests {
166 use super::*;
167
168 #[test]
169 fn test_url_size() {
170 assert_eq!(
172 std::mem::size_of::<Url>(),
173 std::mem::size_of::<*mut c_void>()
174 );
175 }
176}