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