1use std::alloc::{alloc_zeroed, dealloc, handle_alloc_error, Layout};
29use std::cmp::max;
30use std::marker::PhantomData;
31use std::ops::{Index, IndexMut};
32use std::ptr::NonNull;
33use std::sync::Mutex;
34use std::{mem, ptr, usize};
35
36pub struct Subject<T> {
46 layout: Mutex<SubjectLayout>,
47 _phantom: PhantomData<fn(T)>,
48}
49
50struct SubjectLayout {
51 size: usize,
52 align: usize,
53 init_words: Vec<InitWord>,
54 drop_props: Vec<DropProperty>,
55}
56
57struct InitWord {
58 offset: usize,
59 in_use: usize,
60}
61
62struct DropProperty {
63 offset: usize,
64 init_bit_offset: usize,
65 drop: unsafe fn(NonNull<u8>),
66}
67
68struct PropertyInfo {
69 offset: usize,
70 init_bit_offset: usize,
71}
72
73impl<T> Subject<T> {
74 pub fn new() -> Self {
76 Subject {
77 layout: Mutex::new(SubjectLayout {
78 size: 0,
79 align: 1,
80 init_words: Vec::new(),
81 drop_props: Vec::new(),
82 }),
83 _phantom: PhantomData,
84 }
85 }
86
87 pub fn new_prop<'a, P, I: Init<T, P>>(&'a self, initer: I) -> Property<'a, T, P, I> {
90 let info = self.alloc_prop::<P>();
91 return Property {
92 subject: self,
93 offset: info.offset,
94 init_bit_offset: info.init_bit_offset,
95 initer,
96 _phantom: PhantomData,
97 };
98 }
99
100 pub fn new_prop_default_init<'a, P: Default>(&'a self) -> DefaultInitProperty<'a, T, P> {
103 self.new_prop(DefaultInit)
104 }
105
106 pub fn new_prop_const_init<'a, P: Clone>(&'a self, value: P) -> ConstInitProperty<'a, T, P> {
109 self.new_prop(ConstInit { value })
110 }
111
112 pub fn new_prop_fn_init<'a, P, F: Fn(&Extended<T>) -> P>(
132 &'a self,
133 init_fn: F,
134 ) -> FnInitProperty<'a, T, P, F> {
135 self.new_prop(FnInit { init_fn })
136 }
137
138 fn pin_layout(&self) -> Layout {
139 let guard = self.layout.lock().unwrap();
140 unsafe {
141 return Layout::from_size_align_unchecked(guard.size, guard.align);
142 }
143 }
144
145 fn alloc_prop<P>(&self) -> PropertyInfo {
146 let mut layout = self.layout.lock().unwrap();
147 return layout.alloc_prop::<P>();
148 }
149
150 fn free_prop<P>(&self, offset: usize) {
151 if !mem::needs_drop::<P>() {
152 let mut layout = self.layout.lock().unwrap();
153 return layout.free_nodrop_prop(offset);
154 }
155 }
156}
157
158impl SubjectLayout {
159 fn alloc_prop<P>(&mut self) -> PropertyInfo {
160 let init_bit_offset = self.alloc_init_bit();
161 let offset = self.alloc::<P>();
162 if mem::needs_drop::<P>() {
163 let drop = Self::drop_option_in_place::<P>;
164 self.drop_props.push(DropProperty {
165 offset,
166 init_bit_offset,
167 drop,
168 });
169 }
170 return PropertyInfo {
171 offset,
172 init_bit_offset,
173 };
174 }
175
176 unsafe fn drop_option_in_place<P>(ptr: NonNull<u8>) {
177 ptr::drop_in_place(ptr.cast::<Option<P>>().as_ptr());
178 }
179
180 fn alloc_init_bit(&mut self) -> usize {
181 for init_word in self.init_words.iter_mut() {
183 if init_word.in_use != usize::MAX {
184 let bit = init_word.in_use.trailing_ones() as usize;
185 init_word.in_use |= 1 << bit;
186 return init_word.offset * 8 + bit;
187 }
188 }
189
190 let offset = self.alloc::<usize>();
192 let mut in_use = 0;
193 let bit = 0;
194 in_use |= 1 << bit;
195 self.init_words.push(InitWord { offset, in_use });
196 return offset * 8 + bit;
197 }
198
199 fn alloc<P>(&mut self) -> usize {
200 self.alloc_raw(mem::size_of::<P>(), mem::align_of::<P>())
201 }
202
203 fn alloc_raw(&mut self, size: usize, align: usize) -> usize {
204 let offset = (self.size + align - 1) & !(align - 1);
205 self.size = offset + size;
206 self.align = max(self.align, align);
207 return offset;
208 }
209
210 fn free_nodrop_prop(&mut self, _offset: usize) {
211 }
213}
214
215pub struct Property<'a, T, P, I: 'a + Init<T, P>> {
233 subject: &'a Subject<T>,
234 offset: usize,
235 init_bit_offset: usize,
236 initer: I,
237 _phantom: PhantomData<fn() -> P>,
238}
239
240pub type DefaultInitProperty<'a, T, P> = Property<'a, T, P, DefaultInit>;
242
243pub type ConstInitProperty<'a, T, P> = Property<'a, T, P, ConstInit<P>>;
245
246pub type FnInitProperty<'a, T, P, F> = Property<'a, T, P, FnInit<F>>;
248
249pub type DynInitProperty<'a, T, P> = Property<'a, T, P, DynInit<'a, T, P>>;
252
253impl<'a, T, P, I: Init<T, P>> Property<'a, T, P, I> {
254 pub fn subject(&self) -> &Subject<T> {
257 self.subject
258 }
259}
260
261impl<'a, T, P, I: Init<T, P> + Sync> Property<'a, T, P, I> {
262 pub fn into_dyn_init(self) -> DynInitProperty<'a, T, P> {
265 unsafe {
267 let result = Property {
268 subject: self.subject,
269 offset: self.offset,
270 init_bit_offset: self.init_bit_offset,
271 initer: Box::new(ptr::read(&self.initer)) as DynInit<'a, T, P>,
272 _phantom: PhantomData
273 };
274 mem::forget(self);
275 return result;
276 }
277 }
278}
279
280impl<'a, T, P, I: Init<T, P>> Drop for Property<'a, T, P, I> {
281 fn drop(&mut self) {
282 self.subject.free_prop::<P>(self.offset);
283 }
284}
285
286pub trait Init<T, P> {
288 fn init(&self, obj: &Extended<T>) -> P;
290}
291
292pub struct DefaultInit;
294
295pub struct ConstInit<P: Clone> {
297 pub value: P,
298}
299
300pub struct FnInit<F> {
302 pub init_fn: F,
303}
304
305pub type DynInit<'a, T, P> = Box<dyn 'a + Sync + Init<T, P>>;
307
308impl<T, P, F: Fn(&Extended<T>) -> P> Init<T, P> for FnInit<F> {
309 fn init(&self, obj: &Extended<T>) -> P {
310 (self.init_fn)(obj)
311 }
312}
313
314impl<T, P: Clone> Init<T, P> for ConstInit<P> {
315 fn init(&self, _obj: &Extended<T>) -> P {
316 self.value.clone()
317 }
318}
319
320impl<T, P: Default> Init<T, P> for DefaultInit {
321 fn init(&self, _obj: &Extended<T>) -> P {
322 Default::default()
323 }
324}
325
326impl<'a, T, P> Init<T, P> for DynInit<'a, T, P> {
327 fn init(&self, obj: &Extended<T>) -> P {
328 self.as_ref().init(obj)
329 }
330}
331
332pub struct Extended<'a, T> {
355 pub value: T,
356 subject: &'a Subject<T>,
357 data: Mutex<ExtendedData>,
358}
359
360pub type Dynamic<'a> = Extended<'a, ()>;
372
373impl<'a, T> Extended<'a, T> {
374 pub fn new_extend(value: T, subject: &'a Subject<T>) -> Self {
377 Extended {
378 value,
379 subject,
380 data: Mutex::new(ExtendedData::new(subject.pin_layout())),
381 }
382 }
383
384 pub fn subject(&self) -> &Subject<T> {
387 self.subject
388 }
389
390 fn index_raw<P, I: Init<T, P>>(&self, index: &Property<'a, T, P, I>) -> NonNull<P> {
391 if (self.subject as *const Subject<T>) != (index.subject as *const Subject<T>) {
393 panic!("Subject mismatch");
394 }
395
396 let get_data_layout = || self.subject.pin_layout();
398 let init_word_offset = (index.init_bit_offset / 8) & !(mem::align_of::<usize>() - 1);
399 let init_word_bit = index.init_bit_offset - (init_word_offset * 8);
400 unsafe {
401 let mut data = self.data.lock().unwrap();
402 let init_word = data
403 .get_ptr(get_data_layout, init_word_offset)
404 .cast::<usize>()
405 .as_mut();
406 let value_ptr = data.get_ptr(get_data_layout, index.offset).cast::<P>();
407
408 drop(data);
412
413 let init_bit = (*init_word & (1 << init_word_bit)) != 0;
414 if !init_bit {
415 let init_value = index.initer.init(&self);
417
418 let data = self.data.lock().unwrap();
420 let init_bit = (*init_word & (1 << init_word_bit)) != 0;
421 if !init_bit {
422 ptr::write(value_ptr.as_ptr(), init_value);
423 *init_word |= 1 << init_word_bit;
424 }
425 drop(data);
426 }
427 return value_ptr;
428 }
429 }
430}
431
432impl<'a> Dynamic<'a> {
433 pub fn new(subject: &'a Subject<()>) -> Self {
435 Self::new_extend((), subject)
436 }
437}
438
439impl<'a, 'b, T, P, I: Init<T, P>> Index<&'b Property<'a, T, P, I>> for Extended<'b, T> {
440 type Output = P;
441
442 fn index(&self, index: &Property<'a, T, P, I>) -> &Self::Output {
443 unsafe {
444 return &(*self.index_raw(index).as_ref());
445 }
446 }
447}
448
449impl<'a, 'b, T, P, I: Init<T, P>> IndexMut<&'b Property<'a, T, P, I>> for Extended<'b, T> {
450 fn index_mut(&mut self, index: &Property<'a, T, P, I>) -> &mut Self::Output {
451 unsafe {
452 return &mut (*self.index_raw(index).as_mut());
453 }
454 }
455}
456
457impl<'a, T> Drop for Extended<'a, T> {
458 fn drop(&mut self) {
459 let mut data = self.data.lock().unwrap();
460 let layout = self.subject.layout.lock().unwrap();
461 for prop in layout.drop_props.iter() {
462 let get_data_layout = || self.subject.pin_layout();
463 let init_word_offset = (prop.init_bit_offset / 8) & !(mem::align_of::<usize>() - 1);
464 let init_word_bit = prop.init_bit_offset - (init_word_offset * 8);
465 unsafe {
466 let init_word = data
467 .get_ptr(get_data_layout, init_word_offset)
468 .cast::<usize>()
469 .as_mut();
470 let init_bit = (*init_word & (1 << init_word_bit)) != 0;
471 if init_bit {
472 let value_ptr = data.get_ptr(get_data_layout, prop.offset);
474 (prop.drop)(value_ptr);
475 }
476 }
477 }
478 }
479}
480
481struct ExtendedData {
489 head_chunk: Chunk,
490 overflow_chunks: Vec<Chunk>,
491}
492
493struct Chunk {
495 ptr: NonNull<u8>,
496 layout: Layout,
497 data_end: usize,
498}
499
500impl ExtendedData {
501 fn new(head_layout: Layout) -> Self {
502 ExtendedData {
503 head_chunk: Chunk::new(head_layout, head_layout.size()),
504 overflow_chunks: Vec::new(),
505 }
506 }
507
508 fn get_ptr(&mut self, get_data_layout: impl FnOnce() -> Layout, offset: usize) -> NonNull<u8> {
512 if offset < self.head_chunk.data_end {
514 unsafe {
515 return NonNull::new_unchecked(self.head_chunk.ptr.as_ptr().add(offset));
516 }
517 }
518
519 let mut overflow_data_end = self.head_chunk.data_end;
521 match self.overflow_chunks.last() {
522 Some(last_overflow_chunk) => {
523 overflow_data_end = last_overflow_chunk.data_end;
524 if offset < last_overflow_chunk.data_end {
525 let mut lo_chunk_index = 0;
527 let mut hi_chunk_index = self.overflow_chunks.len() - 1;
528 let mut chunk_data_start = self.head_chunk.data_end;
529 loop {
530 if !(lo_chunk_index < hi_chunk_index) {
531 break;
532 }
533 let mid_chunk_index = (lo_chunk_index + hi_chunk_index) / 2;
534 let mid_chunk = &self.overflow_chunks[mid_chunk_index];
535 if offset < mid_chunk.data_end {
536 hi_chunk_index = mid_chunk_index;
537 } else {
538 chunk_data_start = mid_chunk.data_end;
539 lo_chunk_index = mid_chunk_index + 1;
540 }
541 }
542 unsafe {
543 let overflow_chunk = &self.overflow_chunks[lo_chunk_index];
544 return NonNull::new_unchecked(
545 overflow_chunk
546 .ptr
547 .as_ptr()
548 .sub(chunk_data_start)
549 .add(offset),
550 );
551 }
552 }
553 }
554 _ => {}
555 }
556
557 let data_layout = get_data_layout();
559 let new_data_end = data_layout.size();
560 assert!(offset < new_data_end);
561 let chunk_layout =
562 Layout::from_size_align(new_data_end - overflow_data_end, data_layout.align()).unwrap();
563 let overflow_chunk = Chunk::new(chunk_layout, new_data_end);
564 let result = unsafe {
565 NonNull::new_unchecked(
566 overflow_chunk
567 .ptr
568 .as_ptr()
569 .sub(overflow_data_end)
570 .add(offset),
571 )
572 };
573 self.overflow_chunks.push(overflow_chunk);
574 return result;
575 }
576}
577
578impl Chunk {
579 fn new(layout: Layout, data_end: usize) -> Self {
580 let ptr = if layout.size() > 0 {
581 unsafe {
582 match NonNull::new(alloc_zeroed(layout)) {
583 Some(ptr) => ptr,
584 None => handle_alloc_error(layout),
585 }
586 }
587 } else {
588 NonNull::dangling()
589 };
590 Chunk {
591 ptr,
592 layout,
593 data_end,
594 }
595 }
596}
597
598impl Drop for Chunk {
599 fn drop(&mut self) {
600 if self.layout.size() > 0 {
601 unsafe {
602 dealloc(self.ptr.as_ptr(), self.layout);
603 }
604 }
605 }
606}
607
608#[cfg(test)]
609mod tests;