cgp_field/impls/use_field.rs
1use core::marker::PhantomData;
2
3use cgp_component::{IsProviderFor, WithProvider};
4use cgp_type::{ProvideType, TypeComponent};
5
6use crate::traits::{FieldGetter, HasField, HasFieldMut, MutFieldGetter};
7
8/**
9 The `UseField` pattern is used to implement a CGP getter trait by reading
10 the `Tag` field from `Context` via the [`HasField`] trait.
11
12 When a CGP getter component contains only one getter method and is defined
13 using the `#[cgp_getter]` macro, a `UseField` implementation is automatically
14 generated.
15
16 Typically, the `Tag` type would be a type-level string defined through
17 the `Symbol!` macro, such as `Symbol!("name")`. It may also be a type-level
18 integer that is wrapped in the `Index` type, such as `Index<0>`.
19 The `HasField` implementation for these tag types would be automatically
20 implemented following the field names in the struct when `#[derive(HasField)]`
21 is used.
22
23 However, users are free to use any type as the `Tag` type, as there is no
24 additional constraints on what the type should be. The only consequence is
25 that such manual tags would not be automatically implemented by
26 `#[derive(HasField)]`, and so users would have to manually implement the
27 `HasField` instances, or generate them from a different macro.
28
29 `UseField` allows users to easily implement a getter trait for a context
30 by only having to derive the [`HasField`] trait, and specifying the field
31 name through `UseField`. This reduces the amount of boilerplate code required
32 to manually implement the getter trait for each concrete context.
33
34 ## Example
35
36 Given the following getter component definition:
37
38 ```rust,ignore
39 #[cgp_getter(NameGetter)]
40 pub trait HasName {
41 fn name(&self) -> &str;
42 }
43 ```
44
45 The following `UseField` implementation would be generated:
46
47 ```rust,ignore
48 impl<Context, Tag> NameGetter<Context> for UseField<Tag>
49 where
50 Context: HasField<Tag, Value = String>,
51 {
52 fn name(context: &Context) -> &str {
53 &context.get_field(PhantomData).as_str()
54 }
55 }
56 ```
57*/
58pub struct UseField<Tag>(pub PhantomData<Tag>);
59
60pub type WithField<Tag> = WithProvider<UseField<Tag>>;
61
62impl<Context, TypeTag, FieldTag, Field> ProvideType<Context, TypeTag> for UseField<FieldTag>
63where
64 Context: HasField<FieldTag, Value = Field>,
65{
66 type Type = Field;
67}
68
69impl<Context, TypeTag, FieldTag, Field> IsProviderFor<TypeComponent, Context, TypeTag>
70 for UseField<FieldTag>
71where
72 Context: HasField<FieldTag, Value = Field>,
73{
74}
75
76impl<Context, OutTag, Tag, Value> FieldGetter<Context, OutTag> for UseField<Tag>
77where
78 Context: HasField<Tag, Value = Value>,
79{
80 type Value = Value;
81
82 fn get_field(context: &Context, _tag: PhantomData<OutTag>) -> &Value {
83 context.get_field(PhantomData)
84 }
85}
86
87impl<Context, OutTag, Tag, Value> MutFieldGetter<Context, OutTag> for UseField<Tag>
88where
89 Context: HasFieldMut<Tag, Value = Value>,
90{
91 fn get_field_mut(context: &mut Context, _tag: PhantomData<OutTag>) -> &mut Value {
92 context.get_field_mut(PhantomData)
93 }
94}