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}