File: interned-structs_self_ref.rs

package info (click to toggle)
rust-salsa 0.23.0-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 2,424 kB
  • sloc: sh: 12; makefile: 2; javascript: 1
file content (195 lines) | stat: -rw-r--r-- 6,952 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
//! Test that a `tracked` fn on a `salsa::input`
//! compiles and executes successfully.

use std::any::TypeId;
use std::convert::identity;

use salsa::plumbing::Zalsa;
use test_log::test;

#[test]
fn interning_returns_equal_keys_for_equal_data() {
    let db = salsa::DatabaseImpl::new();
    let s1 = InternedString::new(&db, "Hello, ".to_string(), identity);
    let s2 = InternedString::new(&db, "World, ".to_string(), |_| s1);
    let s1_2 = InternedString::new(&db, "Hello, ", identity);
    let s2_2 = InternedString::new(&db, "World, ", |_| s2);
    assert_eq!(s1, s1_2);
    assert_eq!(s2, s2_2);
}
// Recursive expansion of interned macro
// #[salsa::interned]
// struct InternedString<'db> {
//     data: String,
//     other: InternedString<'db>,
// }
// ======================================

#[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
struct InternedString<'db>(
    salsa::Id,
    std::marker::PhantomData<&'db salsa::plumbing::interned::Value<InternedString<'static>>>,
);

#[allow(warnings)]
const _: () = {
    use salsa::plumbing as zalsa_;
    use zalsa_::interned as zalsa_struct_;
    type Configuration_ = InternedString<'static>;
    #[derive(Clone)]
    struct StructData<'db>(String, InternedString<'db>);

    impl<'db> Eq for StructData<'db> {}
    impl<'db> PartialEq for StructData<'db> {
        fn eq(&self, other: &Self) -> bool {
            self.0 == other.0
        }
    }

    impl<'db> std::hash::Hash for StructData<'db> {
        fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
            self.0.hash(state);
        }
    }

    #[doc = r" Key to use during hash lookups. Each field is some type that implements `Lookup<T>`"]
    #[doc = r" for the owned type. This permits interning with an `&str` when a `String` is required and so forth."]
    #[derive(Hash)]
    struct StructKey<'db, T0>(T0, std::marker::PhantomData<&'db ()>);

    impl<'db, T0> zalsa_::interned::HashEqLike<StructKey<'db, T0>> for StructData<'db>
    where
        String: zalsa_::interned::HashEqLike<T0>,
    {
        fn hash<H: std::hash::Hasher>(&self, h: &mut H) {
            zalsa_::interned::HashEqLike::<T0>::hash(&self.0, &mut *h);
        }
        fn eq(&self, data: &StructKey<'db, T0>) -> bool {
            (zalsa_::interned::HashEqLike::<T0>::eq(&self.0, &data.0) && true)
        }
    }
    impl zalsa_struct_::Configuration for Configuration_ {
        const LOCATION: zalsa_::Location = zalsa_::Location {
            file: file!(),
            line: line!(),
        };
        const DEBUG_NAME: &'static str = "InternedString";
        type Fields<'a> = StructData<'a>;
        type Struct<'a> = InternedString<'a>;
    }
    impl Configuration_ {
        pub fn ingredient<Db>(db: &Db) -> &zalsa_struct_::IngredientImpl<Self>
        where
            Db: ?Sized + zalsa_::Database,
        {
            static CACHE: zalsa_::IngredientCache<zalsa_struct_::IngredientImpl<Configuration_>> =
                zalsa_::IngredientCache::new();

            let zalsa = db.zalsa();
            CACHE.get_or_create(zalsa, || {
                zalsa
                    .lookup_jar_by_type::<zalsa_struct_::JarImpl<Configuration_>>()
                    .get_or_create()
            })
        }
    }
    impl zalsa_::AsId for InternedString<'_> {
        fn as_id(&self) -> salsa::Id {
            self.0
        }
    }
    impl zalsa_::FromId for InternedString<'_> {
        fn from_id(id: salsa::Id) -> Self {
            Self(id, std::marker::PhantomData)
        }
    }
    unsafe impl Send for InternedString<'_> {}

    unsafe impl Sync for InternedString<'_> {}

    impl std::fmt::Debug for InternedString<'_> {
        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
            Self::default_debug_fmt(*self, f)
        }
    }
    impl zalsa_::SalsaStructInDb for InternedString<'_> {
        type MemoIngredientMap = zalsa_::MemoIngredientSingletonIndex;

        fn lookup_or_create_ingredient_index(aux: &Zalsa) -> salsa::plumbing::IngredientIndices {
            aux.lookup_jar_by_type::<zalsa_struct_::JarImpl<Configuration_>>()
                .get_or_create()
                .into()
        }

        #[inline]
        fn cast(id: zalsa_::Id, type_id: TypeId) -> Option<Self> {
            if type_id == TypeId::of::<InternedString>() {
                Some(<InternedString as zalsa_::FromId>::from_id(id))
            } else {
                None
            }
        }
    }

    unsafe impl zalsa_::Update for InternedString<'_> {
        unsafe fn maybe_update(old_pointer: *mut Self, new_value: Self) -> bool {
            if unsafe { *old_pointer } != new_value {
                unsafe { *old_pointer = new_value };
                true
            } else {
                false
            }
        }
    }
    impl<'db> InternedString<'db> {
        pub fn new<Db_, T0: zalsa_::interned::Lookup<String> + std::hash::Hash>(
            db: &'db Db_,
            data: T0,
            other: impl FnOnce(InternedString<'db>) -> InternedString<'db>,
        ) -> Self
        where
            Db_: ?Sized + salsa::Database,
            String: zalsa_::interned::HashEqLike<T0>,
        {
            Configuration_::ingredient(db).intern(
                db.as_dyn_database(),
                StructKey::<'db>(data, std::marker::PhantomData::default()),
                |id, data| {
                    StructData(
                        zalsa_::interned::Lookup::into_owned(data.0),
                        other(zalsa_::FromId::from_id(id)),
                    )
                },
            )
        }
        fn data<Db_>(self, db: &'db Db_) -> String
        where
            Db_: ?Sized + zalsa_::Database,
        {
            let fields = Configuration_::ingredient(db).fields(db.as_dyn_database(), self);
            std::clone::Clone::clone((&fields.0))
        }
        fn other<Db_>(self, db: &'db Db_) -> InternedString<'db>
        where
            Db_: ?Sized + zalsa_::Database,
        {
            let fields = Configuration_::ingredient(db).fields(db.as_dyn_database(), self);
            std::clone::Clone::clone((&fields.1))
        }
        #[doc = r" Default debug formatting for this struct (may be useful if you define your own `Debug` impl)"]
        pub fn default_debug_fmt(this: Self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
            zalsa_::with_attached_database(|db| {
                let fields = Configuration_::ingredient(db).fields(db.as_dyn_database(), this);
                let mut f = f.debug_struct("InternedString");
                let f = f.field("data", &fields.0);
                let f = f.field("other", &fields.1);
                f.finish()
            })
            .unwrap_or_else(|| {
                f.debug_tuple("InternedString")
                    .field(&zalsa_::AsId::as_id(&this))
                    .finish()
            })
        }
    }
};