Skip to main content

sway_core/language/ty/expression/
storage.rs

1use super::TyExpression;
2use crate::{engine_threading::*, type_system::TypeId};
3use serde::{Deserialize, Serialize};
4use std::hash::{Hash, Hasher};
5use sway_types::{Ident, Span, Spanned};
6
7/// Describes the full storage access including all the subfields.
8/// E.g.: `storage::ns1::ns2.field1.field2` will be represented as
9/// a `TyStorageAccess` with 2 fields in the `fields` vector: `field1` and `field2`.
10#[derive(Clone, Debug, Serialize, Deserialize)]
11pub struct TyStorageAccess {
12    /// The sequence of field accesses in the storage access expression.
13    /// E.g., for `storage::ns1::ns2.field1.field2`, the fields are `field1` and `field2`.
14    /// Note that the first field is always a field declared in the `storage` declaration,
15    /// and the rest of the fields are struct fields accessed in the storage access expression.
16    pub fields: Vec<TyStorageAccessDescriptor>,
17    /// The full path to the first field in the storage access expression,
18    /// including all the namespace segments and the first field itself,
19    /// without the `storage` keyword.
20    /// E.g., for `storage::ns1::ns2.field1.field2`, the storage field path is `["ns1", "ns2", "field1"]`.
21    pub storage_field_path: Vec<String>,
22    /// The field names in the struct fields access path.
23    /// E.g., for `storage::ns1::ns2.field1.field2.field3`, the struct field names are `["field2", "field3"]`.
24    pub struct_field_names: Vec<String>,
25    /// The key in the `in` keyword expression, if specified for the
26    /// first field in `fields`.
27    pub key_expression: Option<Box<TyExpression>>,
28    pub storage_keyword_span: Span,
29}
30
31impl EqWithEngines for TyStorageAccess {}
32impl PartialEqWithEngines for TyStorageAccess {
33    fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
34        self.fields.len() == other.fields.len()
35            && self.fields.eq(&other.fields, ctx)
36            && self.storage_field_path.len() == other.storage_field_path.len()
37            && self.storage_field_path.eq(&other.storage_field_path)
38            && self.struct_field_names.len() == other.struct_field_names.len()
39            && self.struct_field_names.eq(&other.struct_field_names)
40            && self.key_expression.eq(&other.key_expression, ctx)
41    }
42}
43
44impl HashWithEngines for TyStorageAccess {
45    fn hash<H: Hasher>(&self, state: &mut H, engines: &Engines) {
46        let TyStorageAccess {
47            fields,
48            storage_keyword_span,
49            storage_field_path: storage_field_names,
50            struct_field_names,
51            key_expression,
52        } = self;
53        fields.hash(state, engines);
54        storage_field_names.hash(state);
55        struct_field_names.hash(state);
56        key_expression.hash(state, engines);
57        storage_keyword_span.hash(state);
58    }
59}
60
61impl Spanned for TyStorageAccess {
62    fn span(&self) -> Span {
63        self.fields
64            .iter()
65            .fold(self.fields[0].span.clone(), |acc, field| {
66                Span::join(acc, &field.span)
67            })
68    }
69}
70
71impl TyStorageAccess {
72    pub fn storage_field_name(&self) -> Ident {
73        self.fields[0].name.clone()
74    }
75}
76
77/// Describes a single subfield access in the sequence when accessing a subfield within storage.
78#[derive(Clone, Debug, Serialize, Deserialize)]
79pub struct TyStorageAccessDescriptor {
80    pub name: Ident,
81    pub type_id: TypeId,
82    pub(crate) span: Span,
83}
84
85impl EqWithEngines for TyStorageAccessDescriptor {}
86impl PartialEqWithEngines for TyStorageAccessDescriptor {
87    fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
88        let type_engine = ctx.engines().te();
89        self.name == other.name
90            && type_engine
91                .get(self.type_id)
92                .eq(&type_engine.get(other.type_id), ctx)
93    }
94}
95
96impl HashWithEngines for TyStorageAccessDescriptor {
97    fn hash<H: Hasher>(&self, state: &mut H, engines: &Engines) {
98        let TyStorageAccessDescriptor {
99            name,
100            type_id,
101            // these fields are not hashed because they aren't relevant/a
102            // reliable source of obj v. obj distinction
103            span: _,
104        } = self;
105        let type_engine = engines.te();
106        name.hash(state);
107        type_engine.get(*type_id).hash(state, engines);
108    }
109}