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}