1use std::sync::atomic::{AtomicI32, Ordering};
8use capi::sctypes::{LPVOID, LPCSTR};
9pub use capi::scom::*;
10
11
12pub fn atom(name: &str) -> som_atom_t {
14 let s = s2u!(name);
15 (crate::_API.SciterAtomValue)(s.as_ptr())
16}
17
18pub fn atom_name(id: som_atom_t) -> Option<String> {
20 let mut s = String::new();
21 let ok = (crate::_API.SciterAtomNameCB)(id, crate::utf::store_astr, &mut s as *mut _ as LPVOID);
22 if ok != 0 {
23 Some(s)
24 } else {
25 None
26 }
27}
28
29
30pub trait Passport {
36 fn get_passport(&self) -> &'static som_passport_t;
38}
39
40
41pub struct IAssetRef<T> {
43 asset: *mut som_asset_t,
44 ty: std::marker::PhantomData<T>,
45}
46
47impl<T> Clone for IAssetRef<T> {
48 fn clone(&self) -> Self {
49 self.add_ref();
50 Self {
51 asset: self.asset,
52 ty: self.ty,
53 }
54 }
55}
56
57impl<T> Drop for IAssetRef<T> {
58 fn drop(&mut self) {
59 self.release();
60 }
61}
62
63impl<T> std::fmt::Debug for IAssetRef<T> {
64 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
65 self.add_ref();
67 let rc = self.release();
68
69 let name = self::atom_name(self.get_passport().name);
70 write!(f, "Asset({}):{}", name.unwrap_or_default(), rc)
71 }
72}
73
74impl<T> From<Box<IAsset<T>>> for IAssetRef<T> {
76 fn from(asset: Box<IAsset<T>>) -> Self {
77 Self::from_raw(IAsset::into_raw(asset))
78 }
79}
80
81impl<T> IAssetRef<T> {
82 fn isa(&self) -> &'static som_asset_class_t {
84 unsafe { (*self.asset).isa }
85 }
86
87 fn add_ref(&self) -> i32 {
89 (self.isa().add_ref)(self.asset)
90 }
91
92 fn release(&self) -> i32 {
94 (self.isa().release)(self.asset)
95 }
96}
97
98impl<T> IAssetRef<T> {
99 pub fn from_raw(asset: *mut som_asset_t) -> Self {
101 eprintln!("IAssetRef<{}>::from({:?})", std::any::type_name::<T>(), asset);
102 assert!(!asset.is_null());
103 let me = Self {
104 asset,
105 ty: std::marker::PhantomData,
106 };
107 me.add_ref();
108 me
109 }
110
111 pub fn into_raw(asset: IAssetRef<T>) -> *mut som_asset_t {
113 asset.release();
115
116 let ptr = asset.asset;
118 std::mem::forget(asset);
119
120 ptr
121 }
122
123 pub fn as_ptr(&self) -> *mut som_asset_t {
125 self.asset
126 }
127
128 pub fn as_asset(&self) -> &som_asset_t {
130 unsafe { & *self.asset }
131 }
132
133 pub fn get_passport(&self) -> &som_passport_t {
135 let ptr = (self.isa().get_passport)(self.asset);
137 unsafe { & *ptr }
138 }
139}
140
141
142#[repr(C)]
144pub struct IAsset<T> {
145 asset: som_asset_t,
148 refc: AtomicI32,
149 passport: Option<&'static som_passport_t>,
150 data: T,
151}
152
153pub fn set_global<T>(asset: IAssetRef<T>) {
155 let ptr = asset.as_ptr();
156 (crate::_API.SciterSetGlobalAsset)(ptr);
158}
159
160pub fn into_global<T>(asset: Box<IAsset<T>>) {
162 let ptr = IAsset::into_raw(asset);
163 (crate::_API.SciterSetGlobalAsset)(ptr);
165}
166
167impl<T> std::ops::Deref for IAsset<T> {
168 type Target = T;
169 fn deref(&self) -> &Self::Target {
170 &self.data
171 }
172}
173
174impl<T> std::ops::DerefMut for IAsset<T> {
175 fn deref_mut(&mut self) -> &mut Self::Target {
176 &mut self.data
177 }
178}
179
180impl<T> Drop for IAsset<T> {
181 fn drop(&mut self) {
182 let rc = self.refc.load(Ordering::SeqCst);
183 if rc != 0 {
184 eprintln!("asset<{}>::drop with {} references alive", std::any::type_name::<T>(), rc);
185 }
186 assert_eq!(rc, 0);
187 let ptr = self.asset.isa as *const som_asset_class_t;
189 let ptr = unsafe { Box::from_raw(ptr as *mut som_asset_class_t) };
190 drop(ptr);
191 }
192}
193
194impl<T> IAsset<T> {
195 #[allow(clippy::mut_from_ref)]
197 pub fn from_raw(thing: &*mut som_asset_t) -> &mut IAsset<T> {
198 assert!(!thing.is_null());
199 unsafe { &mut *(*thing as *mut IAsset<T>) }
203 }
204
205 fn into_raw(asset: Box<IAsset<T>>) -> *mut som_asset_t {
207 let p = Box::into_raw(asset);
208 p as *mut som_asset_t
209 }
210}
211
212impl<T: Passport> IAsset<T> {
213 pub fn new(data: T) -> Box<Self> {
215 let isa = Box::new(Self::class());
217
218 let me = Self {
219 asset: som_asset_t { isa: Box::leak(isa) },
220 refc: Default::default(),
221 passport: None,
222 data,
223 };
224 Box::new(me)
225 }
226
227 fn class() -> som_asset_class_t {
228 extern "C" fn asset_add_ref<T>(thing: *mut som_asset_t) -> i32 {
229 {
230 let me = IAsset::<T>::from_raw(&thing);
231 let t = me.refc.fetch_add(1, Ordering::SeqCst) + 1;
232 return t;
234 }
235 }
236 extern "C" fn asset_release<T>(thing: *mut som_asset_t) -> i32 {
237 let t = {
238 let me = IAsset::<T>::from_raw(&thing);
239 me.refc.fetch_sub(1, Ordering::SeqCst) - 1
240 };
241 if t == 0 {
243 let me = unsafe { Box::from_raw(thing as *mut IAsset<T>) };
245 drop(me);
246 }
247 return t;
248 }
249 extern "C" fn asset_get_interface<T>(_thing: *mut som_asset_t, name: LPCSTR, _out: *mut *mut som_asset_t) -> bool {
250 let name = u2s!(name);
251 eprintln!("iasset<T>::get_interface({}) is not implemented.", name);
252 return false;
253 }
254 extern "C" fn asset_get_passport<T: Passport>(thing: *mut som_asset_t) -> *const som_passport_t
255 {
256 let me = IAsset::<T>::from_raw(&thing);
258 if me.passport.is_none() {
259 me.passport = Some(me.data.get_passport());
261 }
262 let ps = me.passport.as_ref().unwrap();
263 return *ps;
264 }
265
266 som_asset_class_t {
267 add_ref: asset_add_ref::<T>,
268 release: asset_release::<T>,
269 get_interface: asset_get_interface::<T>,
270 get_passport: asset_get_passport::<T>,
271 }
272 }
273}