11//! Defines the interface to garbage collected arrays.
22use core:: ops:: Deref ;
33use core:: ptr:: NonNull ;
4+ use core:: cmp:: Ordering ;
5+ use core:: str;
6+ use core:: fmt:: { self , Formatter , Debug , Display } ;
7+ use core:: hash:: { Hash , Hasher } ;
48
59use crate :: { CollectorId , GcSafe , GcRebrand } ;
6- use zerogc_derive:: unsafe_gc_impl;
10+ use zerogc_derive:: { Trace , unsafe_gc_impl} ;
711
812use self :: repr:: GcArrayRepr ;
913
1014pub mod repr;
1115
16+ /// A garbage collected string.
17+ ///
18+ /// This is a transparent wrapper around `GcArray<u8>`,
19+ /// with the additional invariant that it's utf8 encoded.
20+ ///
21+ /// ## Safety
22+ /// The bytes can be assumed to be UTF8 encoded,
23+ /// just like with a `str`.
24+ ///
25+ /// Assuming the bytes are utf8 encoded,
26+ /// this can be transmuted back and forth from `GcArray<u8, Id>`
27+ #[ repr( transparent) ]
28+ #[ derive( Trace , Eq , PartialEq , Hash , Clone , Copy ) ]
29+ #[ zerogc( copy, collector_ids( Id ) ) ]
30+ pub struct GcString < ' gc , Id : CollectorId > {
31+ bytes : GcArray < ' gc , u8 , Id >
32+ }
33+ impl < ' gc , Id : CollectorId > GcString < ' gc , Id > {
34+ /// Convert an array of UTF8 bytes into a string.
35+ ///
36+ /// Returns an error if the bytes aren't valid UTF8,
37+ /// just like [core::str::from_utf8].
38+ #[ inline]
39+ pub fn from_utf8 ( bytes : GcArray < ' gc , u8 , Id > ) -> Result < Self , core:: str:: Utf8Error > {
40+ core:: str:: from_utf8 ( bytes. as_slice ( ) ) ?;
41+ // SAFETY: Validated with from_utf8 call
42+ Ok ( unsafe { Self :: from_utf8_unchecked ( bytes) } )
43+ }
44+ /// Convert an array of UTF8 bytes into a string,
45+ /// without checking for validity.
46+ ///
47+ /// ## Safety
48+ /// Undefined behavior if the bytes aren't valid
49+ /// UTF8, just like with [core::str::from_utf8_unchecked]
50+ #[ inline]
51+ pub unsafe fn from_utf8_unchecked ( bytes : GcArray < ' gc , u8 , Id > ) -> Self {
52+ GcString { bytes }
53+ }
54+ /// Retrieve this string as a raw array of bytes
55+ #[ inline]
56+ pub fn as_bytes ( & self ) -> GcArray < ' gc , u8 , Id > {
57+ self . bytes
58+ }
59+ /// Convert this string into a slice of bytes
60+ #[ inline]
61+ pub fn as_str ( & self ) -> & ' gc str {
62+ unsafe { str:: from_utf8_unchecked ( self . as_bytes ( ) . as_slice ( ) ) }
63+ }
64+ }
65+ impl < ' gc , Id : CollectorId > Deref for GcString < ' gc , Id > {
66+ type Target = str ;
67+ #[ inline]
68+ fn deref ( & self ) -> & ' _ str {
69+ self . as_str ( )
70+ }
71+ }
72+ impl < ' gc , Id : CollectorId > Debug for GcString < ' gc , Id > {
73+ fn fmt ( & self , f : & mut Formatter ) -> fmt:: Result {
74+ Debug :: fmt ( self . as_str ( ) , f)
75+ }
76+ }
77+ impl < ' gc , Id : CollectorId > Display for GcString < ' gc , Id > {
78+ fn fmt ( & self , f : & mut Formatter ) -> fmt:: Result {
79+ Display :: fmt ( self . as_str ( ) , f)
80+ }
81+ }
82+
1283/// A garbage collected array.
1384///
1485/// The length is immutable and cannot change
@@ -65,7 +136,7 @@ impl<'gc, T, Id: CollectorId> GcArray<'gc, T, Id> {
65136 & self . repr
66137 }
67138}
68- impl < ' gc , T : GcSafe < ' gc , Id > , Id : CollectorId > Deref for GcArray < ' gc , T , Id > {
139+ impl < ' gc , T , Id : CollectorId > Deref for GcArray < ' gc , T , Id > {
69140 type Target = [ T ] ;
70141
71142 #[ inline]
@@ -80,6 +151,48 @@ impl<'gc, T, Id: CollectorId> Clone for GcArray<'gc, T, Id> {
80151 * self
81152 }
82153}
154+ impl < ' gc , T : Debug , Id : CollectorId > Debug for GcArray < ' gc , T , Id > {
155+ fn fmt ( & self , f : & mut Formatter ) -> fmt:: Result {
156+ f. debug_list ( ) . entries ( self . iter ( ) ) . finish ( )
157+ }
158+ }
159+ impl < ' gc , T : PartialEq , Id : CollectorId > PartialEq for GcArray < ' gc , T , Id > {
160+ #[ inline]
161+ fn eq ( & self , other : & Self ) -> bool {
162+ self . as_slice ( ) == other. as_slice ( )
163+ }
164+ }
165+ impl < ' gc , T : PartialEq , Id : CollectorId > PartialEq < [ T ] > for GcArray < ' gc , T , Id > {
166+ #[ inline]
167+ fn eq ( & self , other : & [ T ] ) -> bool {
168+ self . as_slice ( ) == other
169+ }
170+ }
171+ impl < ' gc , T : PartialOrd , Id : CollectorId > PartialOrd for GcArray < ' gc , T , Id > {
172+ #[ inline]
173+ fn partial_cmp ( & self , other : & Self ) -> Option < Ordering > {
174+ self . as_slice ( ) . partial_cmp ( other. as_slice ( ) )
175+ }
176+ }
177+ impl < ' gc , T : PartialOrd , Id : CollectorId > PartialOrd < [ T ] > for GcArray < ' gc , T , Id > {
178+ #[ inline]
179+ fn partial_cmp ( & self , other : & [ T ] ) -> Option < Ordering > {
180+ self . as_slice ( ) . partial_cmp ( other)
181+ }
182+ }
183+ impl < ' gc , T : Ord , Id : CollectorId > Ord for GcArray < ' gc , T , Id > {
184+ #[ inline]
185+ fn cmp ( & self , other : & Self ) -> Ordering {
186+ self . as_slice ( ) . cmp ( other)
187+ }
188+ }
189+ impl < ' gc , T : Eq , Id : CollectorId > Eq for GcArray < ' gc , T , Id > { }
190+ impl < ' gc , T : Hash , Id : CollectorId > Hash for GcArray < ' gc , T , Id > {
191+ #[ inline]
192+ fn hash < H : Hasher > ( & self , hasher : & mut H ) {
193+ T :: hash_slice ( self . as_slice ( ) , hasher)
194+ }
195+ }
83196// Need to implement by hand, because [T] is not GcRebrand
84197unsafe_gc_impl ! (
85198 target => GcArray <' gc, T , Id >,
0 commit comments