昨天看了salsa 2022了,发现不懂了. 写了些笔记, 抛砖引玉
PS 2018是什么样子的,我已经忘记了 :)
- Database->Storage
我们从Database::default 进去, 看一下 然后找到 storage: ::core::default::Default::default(), 再看一下 salsa::Storage::default,
pub fn main() {
let mut db = db::Database::default(); //<<<<<
let source_program = SourceProgram::new(&mut db, String::new());
compile::compile(&db, source_program);
let diagnostics = compile::compile::accumulated::<Diagnostics>(&db, source_program);
{
::std::io::_eprint(::core::fmt::Arguments::new_v1(
&["", "\n"],
&[::core::fmt::ArgumentV1::new_debug(&diagnostics)],
));
};
}
#[automatically_derived]
impl ::core::default::Default for Database {
#[inline]
fn default() -> Database {
Database {
storage: ::core::default::Default::default(), <<<<
logs: ::core::default::Default::default(),
}
}
}
pub(crate) struct Database {
storage: salsa::Storage<Self>,
logs: Option<Arc<Mutex<Vec<String>>>>,
}
- Storage->Jar
发现Storage里做了一件事, DB::create_jars(&mut routes); 这里的DB是HasJars. 所以我们要去找
- fn create_jars(routes: &mut salsa::routes::Routes) -> Self::Jars { 或
- impl salsa::storage::HasJars for
impl<DB> Default for Storage<DB>
where
DB: HasJars,
{
fn default() -> Self {
let mut routes = Routes::new();
let jars = DB::create_jars(&mut routes); // <<<<<
Self {
shared: Arc::new(Shared {
jars,
cvar: Default::default(),
}),
routes: Arc::new(routes),
runtime: Runtime::default(),
}
}
}
impl salsa::storage::HasJars for Database {
type Jars = (crate::Jar,);
fn jars(&self) -> (&Self::Jars, &salsa::Runtime) {
self.storage.jars()
}
fn jars_mut(&mut self) -> (&mut Self::Jars, &mut salsa::Runtime) {
self.storage.jars_mut()
}
fn create_jars(routes: &mut salsa::routes::Routes<Self>) -> Self::Jars {
(<crate::Jar as salsa::jar::Jar>::create_jar(routes),) <<<
}
}
- create_jars
注意到 返回值是一个元组, 也就是说,我们给database 多少个Jar,就会在这里有多少个 Jar的create_jar (没有s)
#[salsa::db(crate::Jar)]
pub(crate) struct Database {
storage: salsa::Storage<Self>,
// The logs are only used for testing and demonstrating reuse:
//
logs: Option<Arc<Mutex<Vec<String>>>>,
}
- create_jar
create_jar 是 在 trait of impl<'salsa_db> salsa::jar::Jar 上代码
fn create_jar<DB>(routes: &mut salsa::routes::Routes<DB>) -> Self
where
DB: salsa::storage::JarFromJars<Self> + salsa::storage::DbWithJar<Self>,
{
let i0 =
<crate::compile::compile as salsa::storage::IngredientsFor>::create_ingredients(routes);
....
Self(i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11)
}
- create_ingredients 返回的是 Self::Ingredients,且type Ingredients = Self; 就compile而言, 就是返回compile
先不说具体的 create_ingredients, 我们说一下返回值 compile, 或者说是Jar的成分 ingredients. 即 FunctionIngredient 和 InputFieldIngredient
分别在 functions.rs 和 input_field.rs里
-
在input_field.rs 里有 方法 store,fetch,实现了对 给定hash下,将值存到map里.
-
而 functions.rs 里没有, 但可以在 store.rs里找到store( , 以及 fetch.rs 里 pub fn fetc
salsa::function::FunctionIngredient::new(index, "compile");
salsa::input_field::InputFieldIngredient::new(index, "text");
impl<C> FunctionIngredient<C>
where
C: Configuration,
{
pub fn new(index: IngredientIndex, debug_name: &'static str) -> Self {
Self {
index, //<<<<
memo_map: memo::MemoMap::default(),
lru: Default::default(),
sync_map: Default::default(),
deleted_entries: Default::default(),
registered: Default::default(),
debug_name, //<<<<
}
}
pub struct InputFieldIngredient<K, F> {
index: IngredientIndex,
map: FxHashMap<K, StampedValue<F>>, /// &&&&
debug_name: &'static str,
}
/////// 会 代码生成 修改 Ingredients的
// function
pub struct compile {
intern_map: salsa::interned::IdentityInterner<SourceProgram>,
function: salsa::function::FunctionIngredient<Self>,
}
// struct
pub struct SourceProgram(salsa::Id);
- store.rs里的 store( 和 fetch.rs 里的 fetch(
/// store.rs
pub fn store(
&mut self,
runtime: &mut Runtime,
key: C::Key,
value: C::Value,
durability: Durability,
) {
let revision = runtime.current_revision();
let memo = Memo {
value: Some(value),
verified_at: AtomicCell::new(revision),
revisions: QueryRevisions {
changed_at: revision,
durability,
origin: QueryOrigin::BaseInput,
},
};
if let Some(old_value) = self.memo_map.insert(key, Arc::new(memo)) { // <<<<<<<<<<<<<<<<<<<<<
// NB: we don't have to store `old_value` into `deleted_entries` because we have `&mut self`.
let durability = old_value.load().revisions.durability;
runtime.report_tracked_write(durability);
}
}
pub fn fetch(&self, db: &DynDb<C>, key: C::Key) -> &C::Value {
let runtime = db.runtime();
runtime.unwind_if_revision_cancelled(db);
let StampedValue {
value,
durability,
changed_at,
} = self.compute_value(db, key);
if let Some(evicted) = self.lru.record_use(key.as_id()) {
self.evict(AsId::from_id(evicted));
}
db.runtime().report_tracked_read(
self.database_key_index(key).into(),
durability,
changed_at,
);
value
}
我们回到 impl compile {
发现都做了三件事
- get jar
- get ingredients
- store(when new or set) or fetch(when get)
可以说 数据的结构应该是
Database--Jars--Jar--ingredients--ingredient--map[hash]--value
注意, 在map 之前的 映射关系都是vec[index]这样的硬编码.
impl compile {
#[allow(dead_code, clippy::needless_lifetimes)]
pub fn get<'__db>(db: &'__db dyn crate::Db, source_program: SourceProgram) -> &'__db () {
let (__jar, __runtime) = <_ as salsa::storage::HasJar<crate::Jar>>::jar(db);
let __ingredients =
<_ as salsa::storage::HasIngredientsFor<compile>>::ingredient(__jar);
let __key = __ingredients.intern_map.intern(__runtime, (source_program));
__ingredients.function.fetch(db, __key)
}
#[allow(dead_code, clippy::needless_lifetimes)]
pub fn set(db: &mut dyn crate::Db, source_program: SourceProgram, __value: ()) {
let (__jar, __runtime) = <_ as salsa::storage::HasJar<crate::Jar>>::jar_mut(db);
let __ingredients =
<_ as salsa::storage::HasIngredientsFor<compile>>::ingredient_mut(__jar);
let __key = __ingredients.intern_map.intern(__runtime, (source_program));
__ingredients
.function
.store(__runtime, __key, __value, salsa::Durability::LOW)
}
上面代码 表明了使用时,具体发生了什么, 那么 好像只少了 Database::base create_ingredients硬编码的过程了.
注意 create_jar硬编码 在上面有代码.
- create_ingredients 这里 要补充一个变量 routes, 作用如下:
- 对于一个 compiler(这是一个容器) ,等于 jars.x.y.x 比如 jars.0.0.0
想说 数据 都在 栈上.
- 将这个过程 写为 闭包 |jars| jars.x.y
- 将这个闭包存入routes,得到下标index , 做为 hash返回.
不过routes 里存了两个闭包, 不可变和可变的. 容器里有map.
let index = routes.push(
|jars| {
let jar =
<DB as salsa::storage::JarFromJars<Self::Jar>>::jar_from_jars(jars);
let ingredients =
<_ as salsa::storage::HasIngredientsFor<Self>>::ingredient(jar);
&ingredients.0
},
|jars| {
let jar =
<DB as salsa::storage::JarFromJars<Self::Jar>>::jar_from_jars_mut(
jars,
);
let ingredients =
<_ as salsa::storage::HasIngredientsFor<Self>>::ingredient_mut(jar);
&mut ingredients.0
},
);
impl salsa::storage::HasIngredientsFor<crate::compile::compile> for Jar {
fn ingredient(
&self,
) -> &<crate::compile::compile as salsa::storage::IngredientsFor>::Ingredients { /// 《《《《《《《 IngredientsFor::Ingredients is Self
&self.0
}
fn ingredient_mut(
&mut self,
) -> &mut <crate::compile::compile as salsa::storage::IngredientsFor>::Ingredients {
&mut self.0
}
}
/// 注意1
impl salsa::storage::IngredientsFor for compile {
type Ingredients = Self;
/// 注意2
/// &self.0 即 Ingredients.x x为某struct 或 function 的属性或参数 在 struct 或 function的位置.
也就是说, 根据我们给的schema 硬编码的过程只 生成 database, jars, Ingredients, prop of Ingredient的关系, 并且将一部分关系存到了routes里
》》》 就只是抛砖引玉
ps:请问, 如果我想做序列化, 要怎么做呢? ?_? ?_? ?_? -_-
pub struct Span(salsa::Id);
#[salsa::tracked]
pub struct Span {
pub start: usize,
pub end: usize,
}
评论区
写评论还没有评论