counting_pointer/asc.rs
1// Copyright 2020 Shin Yoshida
2//
3// "LGPL-3.0-or-later OR Apache-2.0 OR BSD-2-Clause"
4//
5// This is part of counting-pointer
6//
7// counting-pointer is free software: you can redistribute it and/or modify
8// it under the terms of the GNU Lesser General Public License as published by
9// the Free Software Foundation, either version 3 of the License, or
10// (at your option) any later version.
11//
12// counting-pointer is distributed in the hope that it will be useful,
13// but WITHOUT ANY WARRANTY; without even the implied warranty of
14// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15// GNU Lesser General Public License for more details.
16//
17// You should have received a copy of the GNU Lesser General Public License
18// along with counting-pointer. If not, see <http://www.gnu.org/licenses/>.
19//
20//
21// Licensed under the Apache License, Version 2.0 (the "License");
22// you may not use this file except in compliance with the License.
23// You may obtain a copy of the License at
24//
25// http://www.apache.org/licenses/LICENSE-2.0
26//
27// Unless required by applicable law or agreed to in writing, software
28// distributed under the License is distributed on an "AS IS" BASIS,
29// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
30// See the License for the specific language governing permissions and
31// limitations under the License.
32//
33//
34// Redistribution and use in source and binary forms, with or without modification, are permitted
35// provided that the following conditions are met:
36//
37// 1. Redistributions of source code must retain the above copyright notice, this list of
38// conditions and the following disclaimer.
39// 2. Redistributions in binary form must reproduce the above copyright notice, this
40// list of conditions and the following disclaimer in the documentation and/or other
41// materials provided with the distribution.
42//
43// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
44// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
45// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
46// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
47// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
48// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
49// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
50// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
51// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
52// POSSIBILITY OF SUCH DAMAGE.
53
54use core::alloc::{GlobalAlloc, Layout};
55use core::any::Any;
56use core::cmp;
57use core::hash::{Hash, Hasher};
58use core::mem::{self, align_of, size_of, MaybeUninit};
59use core::ops::Deref;
60use core::result::Result;
61use core::sync::atomic::{AtomicUsize, Ordering};
62use std::alloc::{handle_alloc_error, System};
63use std::borrow::Borrow;
64use std::fmt;
65
66/// Bucket of `Asc` to allocate/deallocate memory for reference count and value at once.
67#[repr(C)]
68struct Bucket<T: ?Sized> {
69 count: AtomicUsize,
70 size: usize,
71 val: T,
72}
73
74impl<T> From<T> for Bucket<T> {
75 fn from(val: T) -> Self {
76 debug_assert_eq!(align_of::<usize>(), align_of::<Self>());
77
78 Self {
79 count: AtomicUsize::new(1),
80 size: size_of::<Self>(),
81 val,
82 }
83 }
84}
85
86impl<T: ?Sized> Bucket<T> {
87 unsafe fn count(val: &mut T) -> &AtomicUsize {
88 let ptr: *mut T = val;
89 let ptr: *mut usize = ptr.cast();
90 let ptr = ptr.sub(1);
91 let ptr: *const AtomicUsize = ptr.cast();
92 let ptr = ptr.sub(1);
93 &*ptr
94 }
95
96 unsafe fn size(ptr: *const T) -> usize {
97 let ptr: *const usize = ptr.cast();
98 let ptr = ptr.sub(1);
99 *ptr
100 }
101
102 unsafe fn dealloc_ptr(ptr: *mut T) -> *mut u8 {
103 let ptr: *mut usize = ptr.cast();
104 let ptr = ptr.sub(1);
105 let ptr: *const AtomicUsize = ptr.cast();
106 let ptr = ptr.sub(1);
107 ptr as *mut u8
108 }
109}
110
111/// A thread-safe strong reference-counting pointer. 'Asc' stands for 'Atomic Strong Counted.'
112///
113/// It behaves like `std::Sync::Arc` except for that this treats only strong pointer; i.e. `Asc`
114/// gives up weak pointer for the performance.
115///
116/// The inherent methods of `Asc` are all associated funcitons, which means that you have to call
117/// them as e.g., `Asc::get_mut(&mut value)` instead of `value.get_mut()` . This avoids conflicts
118/// with methods of the inner type `T` .
119///
120/// # Thread Safety
121///
122/// Unlike to [`Sc`] , `Asc` uses atomic operations for its reference counting. This means that it
123/// is thread-safe. The disadvangate is that atomic operations are more expensive than ordinary
124/// memory access.
125///
126/// [`Sc`]: struct.Sc.html
127pub struct Asc<T: ?Sized, A = System>
128where
129 A: GlobalAlloc,
130{
131 ptr: *mut T,
132 alloc: A,
133}
134
135unsafe impl<T: ?Sized, A> Sync for Asc<T, A>
136where
137 T: Send + Sync,
138 A: Sync + GlobalAlloc,
139{
140}
141
142unsafe impl<T: ?Sized, A> Send for Asc<T, A>
143where
144 T: Send + Sync,
145 A: Send + GlobalAlloc,
146{
147}
148
149impl<T: ?Sized, A> Drop for Asc<T, A>
150where
151 A: GlobalAlloc,
152{
153 fn drop(&mut self) {
154 unsafe {
155 let count = Bucket::count(&mut *self.ptr).fetch_sub(1, Ordering::Release);
156
157 if count == 1 {
158 let layout =
159 Layout::from_size_align(Bucket::size(self.ptr), align_of::<usize>()).unwrap();
160 let ptr = Bucket::dealloc_ptr(self.ptr);
161
162 self.ptr.drop_in_place();
163 self.alloc.dealloc(ptr, layout);
164 }
165 }
166 }
167}
168
169impl<T, A> Default for Asc<T, A>
170where
171 T: Default,
172 A: Default + GlobalAlloc,
173{
174 fn default() -> Self {
175 Self::new(T::default(), A::default())
176 }
177}
178
179impl<T, A> From<T> for Asc<T, A>
180where
181 A: Default + GlobalAlloc,
182{
183 fn from(val: T) -> Self {
184 Self::new(val, A::default())
185 }
186}
187
188impl<T, A> From<&'_ [T]> for Asc<[T], A>
189where
190 T: Clone,
191 A: Default + GlobalAlloc,
192{
193 fn from(vals: &'_ [T]) -> Self {
194 Asc::<T, A>::from_slice_alloc(vals, A::default())
195 }
196}
197
198impl<T: ?Sized, A> Clone for Asc<T, A>
199where
200 A: Clone + GlobalAlloc,
201{
202 fn clone(&self) -> Self {
203 // increment the count.
204 unsafe {
205 let val = &mut *self.ptr;
206 Bucket::count(val).fetch_add(1, Ordering::Acquire);
207 };
208
209 Self {
210 ptr: self.ptr,
211 alloc: self.alloc.clone(),
212 }
213 }
214}
215
216impl<T, A> Asc<T, A>
217where
218 A: GlobalAlloc,
219{
220 /// Creates a new instance.
221 ///
222 /// # Examples
223 ///
224 /// ```
225 /// use std::alloc::System;
226 /// use counting_pointer::Asc;
227 ///
228 /// let _five = Asc::new(5, System);
229 /// ```
230 pub fn new(val: T, alloc: A) -> Self {
231 let bucket = unsafe {
232 let layout = Layout::new::<Bucket<T>>();
233 let ptr = alloc.alloc(layout) as *mut Bucket<T>;
234 if ptr.is_null() {
235 handle_alloc_error(layout);
236 }
237
238 ptr.write(Bucket::from(val));
239 &mut *ptr
240 };
241 Self {
242 ptr: &mut bucket.val,
243 alloc,
244 }
245 }
246
247 /// Creates a new instance of `Asc<[T], A>` .
248 ///
249 /// # Examples
250 ///
251 /// ```
252 /// use std::alloc::System;
253 /// use counting_pointer::Asc;
254 ///
255 /// let vals: [i32; 4] = [0, 1, 2, 3];
256 /// let sc = Asc::from_slice_alloc(&vals, System);
257 /// assert_eq!(&vals, &*sc);
258 /// ```
259 pub fn from_slice_alloc(vals: &[T], alloc: A) -> Asc<[T], A>
260 where
261 T: Clone,
262 {
263 unsafe {
264 let layout = {
265 let align = align_of::<Bucket<T>>();
266 let size = size_of::<Bucket<T>>() - size_of::<Bucket<T>>()
267 + vals.len() * size_of::<Bucket<T>>();
268 Layout::from_size_align_unchecked(size, align)
269 };
270
271 let ptr = alloc.alloc(layout) as *mut Bucket<T>;
272 if ptr.is_null() {
273 handle_alloc_error(layout);
274 }
275
276 let mut bucket = &mut *ptr;
277 bucket.count = AtomicUsize::new(1);
278 bucket.size = layout.size();
279
280 let ptr = &mut bucket.val as *mut T;
281 for i in 0..vals.len() {
282 let v = vals[i].clone();
283 let ptr = ptr.add(i);
284 ptr.write(v);
285 }
286
287 let slice_ref = core::slice::from_raw_parts_mut(ptr, vals.len());
288 Asc::<[T], A> {
289 ptr: &mut *slice_ref,
290 alloc,
291 }
292 }
293 }
294}
295
296impl<A> Asc<dyn Any, A>
297where
298 A: GlobalAlloc,
299{
300 /// Creates `Asc<dyn Any>` instance.
301 ///
302 /// # Examples
303 ///
304 /// ```
305 /// use std::alloc::System;
306 /// use counting_pointer::Asc;
307 ///
308 /// let _five = Asc::new_any(5, System);
309 /// ```
310 pub fn new_any<T>(val: T, alloc: A) -> Self
311 where
312 T: Any,
313 {
314 let bucket = unsafe {
315 let layout = Layout::new::<Bucket<T>>();
316 let ptr = alloc.alloc(layout) as *mut Bucket<T>;
317 if ptr.is_null() {
318 handle_alloc_error(layout);
319 }
320
321 ptr.write(Bucket::from(val));
322 &mut *ptr
323 };
324 Self {
325 ptr: &mut bucket.val,
326 alloc,
327 }
328 }
329}
330
331impl<T: ?Sized, A> fmt::Debug for Asc<T, A>
332where
333 A: fmt::Debug + GlobalAlloc,
334{
335 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
336 let ptr = format!("{:p}", self.ptr);
337 let alloc = format!("{:?}", self.alloc);
338
339 f.debug_struct("Asc")
340 .field("ptr", &ptr)
341 .field("alloc", &alloc)
342 .finish()
343 }
344}
345
346impl<T: ?Sized, A> PartialEq for Asc<T, A>
347where
348 T: PartialEq,
349 A: GlobalAlloc,
350{
351 fn eq(&self, other: &Self) -> bool {
352 let this: &T = self.borrow();
353 let other: &T = other.borrow();
354 this.eq(other)
355 }
356}
357
358impl<T: ?Sized, A> Eq for Asc<T, A>
359where
360 T: Eq,
361 A: GlobalAlloc,
362{
363}
364
365impl<T: ?Sized, A> PartialOrd for Asc<T, A>
366where
367 T: PartialOrd,
368 A: GlobalAlloc,
369{
370 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
371 let this: &T = self.borrow();
372 let other: &T = other.borrow();
373 this.partial_cmp(other)
374 }
375}
376
377impl<T: ?Sized, A> Ord for Asc<T, A>
378where
379 T: Ord,
380 A: GlobalAlloc,
381{
382 fn cmp(&self, other: &Self) -> cmp::Ordering {
383 let this: &T = self.borrow();
384 let other: &T = other.borrow();
385 this.cmp(other)
386 }
387}
388
389impl<T: ?Sized, A> Hash for Asc<T, A>
390where
391 T: Hash,
392 A: GlobalAlloc,
393{
394 fn hash<H>(&self, hasher: &mut H)
395 where
396 H: Hasher,
397 {
398 let inner: &T = self.borrow();
399 inner.hash(hasher);
400 }
401}
402
403impl<T: ?Sized, A> fmt::Display for Asc<T, A>
404where
405 T: fmt::Display,
406 A: GlobalAlloc,
407{
408 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
409 let inner: &T = self.deref();
410 fmt::Display::fmt(inner, f)
411 }
412}
413
414impl<T: ?Sized, A> AsRef<T> for Asc<T, A>
415where
416 A: GlobalAlloc,
417{
418 fn as_ref(&self) -> &T {
419 self.deref()
420 }
421}
422
423impl<T: ?Sized, A> Borrow<T> for Asc<T, A>
424where
425 A: GlobalAlloc,
426{
427 fn borrow(&self) -> &T {
428 self.deref()
429 }
430}
431
432impl<T: ?Sized, A> Deref for Asc<T, A>
433where
434 A: GlobalAlloc,
435{
436 type Target = T;
437
438 fn deref(&self) -> &Self::Target {
439 unsafe { &*self.ptr }
440 }
441}
442
443impl<T, A> Asc<T, A>
444where
445 A: GlobalAlloc,
446{
447 /// Consumes `this`, returning `Asc<dyn Any, A>`
448 ///
449 /// # Examples
450 ///
451 /// ```
452 /// use counting_pointer::Asc;
453 ///
454 /// let sc: Asc<i32> = Asc::from(6);
455 /// let any = Asc::to_any(sc);
456 /// ```
457 pub fn to_any(this: Self) -> Asc<dyn Any, A>
458 where
459 T: Any,
460 {
461 let (ptr, alloc) = Self::decouple(this);
462 Asc::<dyn Any, A> { ptr, alloc }
463 }
464}
465
466impl<T: ?Sized, A> Asc<T, A>
467where
468 A: GlobalAlloc,
469{
470 /// Provides a raw pointer to the data.
471 ///
472 /// The counts are not affected in any way and the `Asc` is not consumed. The pointer is valid
473 /// for as long as another `Asc` instance is pointing to the address.
474 ///
475 /// # Examples
476 ///
477 /// ```
478 /// use counting_pointer::Asc;
479 ///
480 /// let x: Asc<String> = Asc::from(String::from("Hello"));
481 /// let x_ptr = Asc::as_ptr(&x);
482 /// assert_eq!("Hello", unsafe { &*x_ptr });
483 /// ```
484 pub fn as_ptr(this: &Self) -> *const T {
485 this.ptr
486 }
487
488 /// Returns the number of `Asc` pointers pointing to the same address.
489 ///
490 /// # Examples
491 ///
492 /// ```
493 /// use counting_pointer::Asc;
494 ///
495 /// let five: Asc<i32> = Asc::from(5);
496 /// assert_eq!(1, Asc::count(&five));
497 ///
498 /// let _also_five = five.clone();
499 /// assert_eq!(2, Asc::count(&five));
500 /// assert_eq!(2, Asc::count(&_also_five));
501 ///
502 /// drop(five);
503 /// assert_eq!(1, Asc::count(&_also_five));
504 /// ```
505 pub fn count(this: &Self) -> usize {
506 unsafe {
507 let val = &mut *this.ptr;
508 Bucket::count(val).load(Ordering::Relaxed)
509 }
510 }
511
512 /// Returns a mutable reference into the given `Asc` , if no other `Asc` instance is pointing to
513 /// the same address; otherwise returns `None` .
514 ///
515 /// See also [`make_mut`] , which will `clone` the inner value when some other `Asc` instances
516 /// are.
517 ///
518 /// [`make_mut`]: #method.make_mut
519 ///
520 /// # Examples
521 ///
522 /// ```
523 /// use counting_pointer::Asc;
524 ///
525 /// let mut x: Asc<i32> = Asc::from(3);
526 /// assert_eq!(3, *x);
527 ///
528 /// *Asc::get_mut(&mut x).unwrap() = 4;
529 /// assert_eq!(4, *x);
530 ///
531 /// let _y = x.clone();
532 /// let n = Asc::get_mut(&mut x);
533 /// assert!(n.is_none());
534 /// ```
535 pub fn get_mut(this: &mut Self) -> Option<&mut T> {
536 if Self::count(this) == 1 {
537 Some(unsafe { &mut *this.ptr })
538 } else {
539 None
540 }
541 }
542
543 /// Returns `true` if the two `Asc` instances point to the same address, or `false` .
544 ///
545 /// # Examples
546 ///
547 /// ```
548 /// use counting_pointer::Asc;
549 ///
550 /// let five: Asc<i32> = Asc::from(5);
551 /// let same_five = five.clone();
552 /// let other_five: Asc<i32> = Asc::from(5);
553 ///
554 /// assert_eq!(true, Asc::ptr_eq(&five, &same_five));
555 /// assert_eq!(false, Asc::ptr_eq(&five, &other_five));
556 /// ```
557 pub fn ptr_eq(this: &Self, other: &Self) -> bool {
558 Asc::as_ptr(this) == Asc::as_ptr(other)
559 }
560
561 /// Consumes `this` , returning the wrapped pointer and the allocator.
562 ///
563 /// To avoid memory leak, the returned pointer must be converted back to an `Asc` using
564 /// [`from_raw_alloc`] .
565 ///
566 /// Using this function and [`from_raw_alloc`] , user can create an `Asc<T: ?Sized>` instance.
567 ///
568 /// [`from_raw_alloc`]: #method.from_raw_alloc
569 ///
570 /// # Examples
571 ///
572 /// ```
573 /// use counting_pointer::Asc;
574 ///
575 /// let asc: Asc<String> = Asc::from("Foo".to_string());
576 /// let (ptr, alloc) = Asc::into_raw_alloc(asc);
577 /// let _asc: Asc<dyn AsRef<str>> = unsafe { Asc::from_raw_alloc(ptr, alloc) };
578 /// ```
579 pub fn into_raw_alloc(this: Self) -> (*const T, A) {
580 let (ptr, alloc) = Self::decouple(this);
581 (ptr, alloc)
582 }
583
584 /// Constructs a new instance from a raw pointer and allocator.
585 ///
586 /// The raw pointer must have been previously returned by a call to [`into_raw_alloc`] .
587 ///
588 /// Using this function and [`into_raw_alloc`] , user can create an `Asc<T: ?Sized>` instance.
589 ///
590 /// # Safety
591 ///
592 /// It may lead to memory unsafety to use improperly, even if the returned value will never be
593 /// accessed.
594 ///
595 /// [`into_raw_alloc`]: #method.into_raw_alloc
596 ///
597 /// # Examples
598 ///
599 /// ```
600 /// use counting_pointer::Asc;
601 ///
602 /// let asc: Asc<String> = Asc::from("Foo".to_string());
603 /// let (ptr, alloc) = Asc::into_raw_alloc(asc);
604 /// let _asc: Asc<dyn AsRef<str>> = unsafe { Asc::from_raw_alloc(ptr, alloc) };
605 /// ```
606 pub unsafe fn from_raw_alloc(ptr: *const T, alloc: A) -> Self {
607 Self {
608 ptr: ptr as *mut T,
609 alloc,
610 }
611 }
612
613 fn decouple(this: Self) -> (*mut T, A) {
614 let alloc = unsafe {
615 let mut alloc = MaybeUninit::<A>::uninit();
616 let ptr = alloc.as_mut_ptr();
617 ptr.copy_from_nonoverlapping(&this.alloc, 1);
618 alloc.assume_init()
619 };
620
621 let ret = (this.ptr, alloc);
622 mem::forget(this);
623 ret
624 }
625}
626
627impl<T: Clone, A: Clone> Asc<T, A>
628where
629 A: GlobalAlloc,
630{
631 /// Makes a mutable reference into the given `Asc` .
632 ///
633 /// If another `Asc` instance is pointing to the same address, `make_mut` will `clone` the inner
634 /// value to a new allocation to ensure unique ownership.
635 ///
636 /// See also [`get_mut`] , which will fail rather than cloning.
637 ///
638 /// [`get_mut`]: #method.get_mut
639 ///
640 /// # Examples
641 ///
642 /// ```
643 /// use counting_pointer::Asc;
644 ///
645 /// let mut data: Asc<i32> = Asc::from(5);
646 /// assert_eq!(5, *data);
647 ///
648 /// *Asc::make_mut(&mut data) += 1; // Won't clone anything.
649 /// assert_eq!(6, *data);
650 ///
651 /// let mut data2 = data.clone(); // Won't clone the inner data.
652 /// *Asc::make_mut(&mut data) += 1; // Clones inner data.
653 /// assert_eq!(7, *data);
654 /// assert_eq!(6, *data2);
655 /// ```
656 pub fn make_mut(this: &mut Self) -> &mut T {
657 if Self::count(this) != 1 {
658 let val: &T = this.deref();
659 *this = Asc::new(val.clone(), this.alloc.clone());
660 }
661
662 unsafe { &mut *this.ptr }
663 }
664}
665
666impl<A> Asc<dyn Any, A>
667where
668 A: GlobalAlloc,
669{
670 /// Attempts to downcast the `Asc<dyn Any, A>` to a concrete type.
671 ///
672 /// # Examples
673 ///
674 /// ```
675 /// use std::alloc::System;
676 /// use std::any::Any;
677 /// use counting_pointer::Asc;
678 ///
679 /// let sc = Asc::new_any(8 as i32, System);
680 ///
681 /// let success = Asc::downcast::<i32>(sc.clone()).unwrap();
682 /// assert_eq!(8, *success);
683 ///
684 /// let fail = Asc::downcast::<String>(sc.clone());
685 /// assert_eq!(true, fail.is_err());
686 /// ```
687 pub fn downcast<T: Any>(self) -> Result<Asc<T, A>, Self> {
688 let val: &mut dyn Any = unsafe { &mut *self.ptr };
689 match val.downcast_mut() {
690 None => Err(self),
691 Some(t) => {
692 let (_, alloc) = Self::decouple(self);
693 Ok(Asc::<T, A> {
694 ptr: t as *mut T,
695 alloc,
696 })
697 }
698 }
699 }
700}
701
702#[cfg(test)]
703mod tests {
704 use super::*;
705 use gharial::{GAlloc, GBox};
706
707 #[test]
708 fn new() {
709 let five = GBox::from(5);
710 let _five = Asc::new(five, GAlloc::default());
711 }
712
713 #[test]
714 fn clone() {
715 let five = GBox::from(5);
716
717 let five = Asc::new(five, GAlloc::default());
718 let _cloned = five.clone();
719 }
720
721 #[test]
722 fn make_mut() {
723 let inner = GBox::from(5);
724
725 let mut data = Asc::new(inner, GAlloc::default());
726 {
727 let _mr = Asc::make_mut(&mut data);
728 }
729
730 let _data2 = data.clone();
731 {
732 let _mr = Asc::make_mut(&mut data);
733 }
734 }
735
736 #[test]
737 fn downcast() {
738 let inner = GBox::from(8);
739
740 let sc = Asc::new_any(inner, GAlloc::default());
741
742 let ok = Asc::downcast::<GBox<i32>>(sc.clone());
743 assert_eq!(true, ok.is_ok());
744
745 let fail = Asc::downcast::<String>(sc.clone());
746 assert_eq!(true, fail.is_err());
747 }
748
749 #[test]
750 fn to_any() {
751 let inner = GBox::from(6);
752
753 let sc = Asc::new(inner, GAlloc::default());
754 let _any = Asc::to_any(sc);
755 }
756
757 #[test]
758 fn from_slice_alloc() {
759 let inners: [GBox<i32>; 2] = [GBox::from(6), GBox::from(4)];
760
761 let _sc = Asc::from_slice_alloc(&inners, GAlloc::default());
762 }
763
764 #[test]
765 fn raw_alloc() {
766 let asc: Asc<GBox<i32>> = Asc::from(GBox::from(0));
767 let (ptr, alloc) = Asc::into_raw_alloc(asc);
768 let _sc = unsafe { Asc::from_raw_alloc(ptr, alloc) };
769 }
770}