1
1
//! Defines the interface to garbage collected arrays.
2
2
use core:: ops:: Deref ;
3
3
use 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 } ;
4
8
5
9
use crate :: { CollectorId , GcSafe , GcRebrand } ;
6
- use zerogc_derive:: unsafe_gc_impl;
10
+ use zerogc_derive:: { Trace , unsafe_gc_impl} ;
7
11
8
12
use self :: repr:: GcArrayRepr ;
9
13
10
14
pub mod repr;
11
15
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
+
12
83
/// A garbage collected array.
13
84
///
14
85
/// The length is immutable and cannot change
@@ -65,7 +136,7 @@ impl<'gc, T, Id: CollectorId> GcArray<'gc, T, Id> {
65
136
& self . repr
66
137
}
67
138
}
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 > {
69
140
type Target = [ T ] ;
70
141
71
142
#[ inline]
@@ -80,6 +151,48 @@ impl<'gc, T, Id: CollectorId> Clone for GcArray<'gc, T, Id> {
80
151
* self
81
152
}
82
153
}
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
+ }
83
196
// Need to implement by hand, because [T] is not GcRebrand
84
197
unsafe_gc_impl ! (
85
198
target => GcArray <' gc, T , Id >,
0 commit comments