@@ -7,7 +7,7 @@ This crate provides abstractions for creating
7
7
[ type witnesses] ( #what-are-type-witnesses ) .
8
8
9
9
The inciting motivation for this crate is emulating trait polymorphism in ` const fn `
10
- (as of 2023-07-31 , it's not possible to call trait methods in const contexts on stable).
10
+ (as of 2023-09-10 , it's not possible to call trait methods in const contexts on stable).
11
11
12
12
# What are type witnesses
13
13
@@ -27,7 +27,7 @@ which can coerce between a type parameter and as many types as there are variant
27
27
### Polymorphic function
28
28
29
29
This demonstrates how one can write a return-type-polymorphic ` const fn `
30
- (as of 2023-07-31 , trait methods can't be called in const fns)
30
+ (as of 2023-09-10 , trait methods can't be called in const fns on stable )
31
31
32
32
``` rust
33
33
use typewit :: {MakeTypeWitness , TypeEq };
@@ -75,7 +75,7 @@ typewit::simple_type_witness! {
75
75
This function demonstrates const fn polymorphism
76
76
and projecting [ ` TypeEq ` ] by implementing [ ` TypeFn ` ] .
77
77
78
- (this example requires Rust 1.61 .0, because of the ` I: SliceIndex<T>, ` bound)
78
+ (this example requires Rust 1.71 .0, because it uses ` <[T]>::split_at ` in a const context.
79
79
``` rust
80
80
use std :: ops :: Range ;
81
81
@@ -154,6 +154,12 @@ typewit::type_fn! {
154
154
155
155
impl <I : SliceIndex <T >> I => SliceIndexRet <I , T >
156
156
}
157
+
158
+ const fn slice_range <T >(slice : & [T ], range : Range <usize >) -> & [T ] {
159
+ let suffix = slice . split_at (range . start). 1 ;
160
+ suffix . split_at (range . end - range . start). 0
161
+ }
162
+
157
163
```
158
164
159
165
When the wrong type is passed for the index,
@@ -217,6 +223,156 @@ typewit::type_fn!{
217
223
impl <const N : usize > Usize <N > => Arr <N >
218
224
}
219
225
```
226
+ ### Builder
227
+
228
+ Using a type witness to help encode a type-level enum,
229
+ and to match on that type-level enum inside of a function.
230
+
231
+ The type-level enum is used to track the initialization of fields in a builder.
232
+
233
+ This example requires Rust 1.65.0, because it uses Generic Associated Types.
234
+ ``` rust
235
+ use typewit :: HasTypeWitness ;
236
+
237
+ fn main () {
238
+ // all default fields
239
+ assert_eq! (
240
+ StructBuilder :: new (). build (),
241
+ Struct {foo : " default value" . into (), bar : vec! [3 , 5 , 8 ]},
242
+ );
243
+
244
+ // defaulted bar field
245
+ assert_eq! (
246
+ StructBuilder :: new (). foo (" hello" ). build (),
247
+ Struct {foo : " hello" . into (), bar : vec! [3 , 5 , 8 ]},
248
+ );
249
+
250
+ // defaulted foo field
251
+ assert_eq! (
252
+ StructBuilder :: new (). bar ([13 , 21 , 34 ]). build (),
253
+ Struct {foo : " default value" . into (), bar : vec! [13 , 21 , 34 ]},
254
+ );
255
+
256
+ // all initialized fields
257
+ assert_eq! (
258
+ StructBuilder :: new (). foo (" world" ). bar ([55 , 89 ]). build (),
259
+ Struct {foo : " world" . into (), bar : vec! [55 , 89 ]},
260
+ );
261
+ }
262
+
263
+
264
+ #[derive(Debug , PartialEq , Eq )]
265
+ struct Struct {
266
+ foo : String ,
267
+ bar : Vec <u32 >,
268
+ }
269
+
270
+ struct StructBuilder <FooInit : InitState , BarInit : InitState > {
271
+ // If `FooInit` is `Uninit`, then this field is a `()`
272
+ // If `FooInit` is `Init`, then this field is a `String`
273
+ foo : BuilderField <FooInit , String >,
274
+
275
+ // If `BarInit` is `Uninit`, then this field is a `()`
276
+ // If `BarInit` is `Init`, then this field is a `Vec<u32>`
277
+ bar : BuilderField <BarInit , Vec <u32 >>,
278
+ }
279
+
280
+ impl StructBuilder <Uninit , Uninit > {
281
+ pub const fn new () -> Self {
282
+ Self {
283
+ foo : (),
284
+ bar : (),
285
+ }
286
+ }
287
+ }
288
+
289
+ impl <FooInit : InitState , BarInit : InitState > StructBuilder <FooInit , BarInit > {
290
+ /// Sets the `foo` field
291
+ pub fn foo (self , foo : impl Into <String >) -> StructBuilder <Init , BarInit > {
292
+ StructBuilder {
293
+ foo : foo . into (),
294
+ bar : self . bar,
295
+ }
296
+ }
297
+
298
+ /// Sets the `bar` field
299
+ pub fn bar (self , bar : impl Into <Vec <u32 >>) -> StructBuilder <FooInit , Init > {
300
+ StructBuilder {
301
+ foo : self . foo,
302
+ bar : bar . into (),
303
+ }
304
+ }
305
+
306
+ /// Builds `Struct`,
307
+ /// providing default values for fields that haven't been set.
308
+ pub fn build (self ) -> Struct {
309
+ typewit :: type_fn! {
310
+ struct HelperFn <T >;
311
+ impl <I : InitState > I => BuilderField <I , T >
312
+ }
313
+
314
+ Struct {
315
+ // matching on the type-level `InitState` enum by using `InitWit`.
316
+ // `WITNESS` comes from the `HasTypeWitness` trait
317
+ foo : match FooInit :: WITNESS {
318
+ // `te: TypeEq<FooInit, Init>`
319
+ InitWit :: InitW (te ) => {
320
+ te . map (HelperFn :: NEW ) // : TypeEq<BuilderField<FooInit, String>, String>
321
+ . to_right (self . foo)
322
+ }
323
+ InitWit :: UninitW (_ ) => " default value" . to_string (),
324
+ },
325
+ bar : match BarInit :: WITNESS {
326
+ // `te: TypeEq<BarInit, Init>`
327
+ InitWit :: InitW (te ) => {
328
+ te . map (HelperFn :: NEW ) // : TypeEq<BuilderField<BarInit, Vec<u32>>, Vec<u32>>
329
+ . to_right (self . bar)
330
+ }
331
+ InitWit :: UninitW (_ ) => vec! [3 , 5 , 8 ],
332
+ },
333
+ }
334
+ }
335
+ }
336
+
337
+ // Emulates a type-level `enum InitState { Init, Uninit }`
338
+ trait InitState : Sized + HasTypeWitness <InitWit <Self >> {
339
+ // How a builder represents an initialized/uninitialized field.
340
+ // If `Self` is `Uninit`, then this is `()`.
341
+ // If `Self` is `Init`, then this is `T`.
342
+ type BuilderField <T >;
343
+ }
344
+
345
+ // If `I` is `Uninit`, then this evaluates to `()`
346
+ // If `I` is `Init`, then this evaluates to `T`
347
+ type BuilderField <I , T > = <I as InitState >:: BuilderField :: <T >;
348
+
349
+ // Emulates a type-level `InitState::Init` variant.
350
+ // Marks a field as initialized.
351
+ enum Init {}
352
+
353
+ impl InitState for Init {
354
+ type BuilderField <T > = T ;
355
+ }
356
+
357
+ // Emulates a type-level `InitState::Uninit` variant
358
+ // Marks a field as uninitialized.
359
+ enum Uninit {}
360
+
361
+ impl InitState for Uninit {
362
+ type BuilderField <T > = ();
363
+ }
364
+
365
+ typewit :: simple_type_witness! {
366
+ // Declares `enum InitWit<__Wit>`, a type witness.
367
+ // (the `__Wit` type parameter is implicitly added after all generics)
368
+ enum InitWit {
369
+ // This variant requires `__Wit == Init`
370
+ InitW = Init ,
371
+ // This variant requires `__Wit == Uninit`
372
+ UninitW = Uninit ,
373
+ }
374
+ }
375
+ ```
220
376
221
377
222
378
# Cargo features
0 commit comments