Skip to main content

cartel_sqlite/runtime/
layout.rs

1use crate::{
2    catalogs, config, database, open,
3    runtime::{self, heap, local},
4};
5use dope_core::driver::settings::{claim, errors};
6use dope_core::driver::{
7    settings::{self, demands, demands::slots::Slots},
8    storage,
9};
10use dope_runtime::topology;
11use heap::layout;
12use std::marker;
13
14/// Exact SQLite storage factory for one driver domain and query catalog.
15pub struct Layout<'sql, I: catalogs::Catalog> {
16    settings: local::Settings,
17    sqlite: layout::Layout,
18    database: database::Target<'sql>,
19    statement_bytes: usize,
20    lookaside: crate::memory::Lookaside,
21    marker: marker::PhantomData<I>,
22}
23
24impl<'sql, I: catalogs::Catalog> Layout<'sql, I> {
25    pub(super) const fn dimensions(&self) -> (layout::Layout, usize, usize, usize) {
26        (
27            self.sqlite,
28            self.settings.config.result_bytes(),
29            self.statement_bytes,
30            self.lookaside.bytes(),
31        )
32    }
33
34    pub(super) fn into_parts(
35        self,
36    ) -> (
37        local::Settings,
38        database::Target<'sql>,
39        crate::memory::Lookaside,
40    ) {
41        (self.settings, self.database, self.lookaside)
42    }
43}
44
45impl<'sql> database::Target<'sql> {
46    pub fn plan<I: catalogs::Catalog>(
47        self,
48        limits: crate::Limits,
49        memory: crate::Memory,
50    ) -> Result<topology::Plan<Layout<'sql, I>, open::Plan<I>>, database::Error> {
51        catalogs::validate::<I>().map_err(database::Error::Catalog)?;
52        let config = config::Config::from_parts(limits, memory)?;
53        let (plan, sqlite) = memory.admit::<I>().map_err(database::Error::Runtime)?;
54        if plan.targets.retained > sqlite.capacity() {
55            return Err(database::Error::Runtime(runtime::Error::SqliteCapacity));
56        }
57        let values = sqlite.capacity();
58        if values > i32::MAX as usize {
59            return Err(database::Error::Runtime(runtime::Error::SqliteMemory {
60                actual: values,
61            }));
62        }
63        let actual = plan.statements.sql_bytes.max(self.sql_bytes());
64        if actual > i32::MAX as usize {
65            return Err(database::Error::Runtime(
66                runtime::Error::StatementSqlBytes { actual },
67            ));
68        }
69        let sql = actual as i32;
70        let layout = Layout {
71            settings: local::Settings {
72                config,
73                value_bytes: values as i32,
74                statement_sql_bytes: sql,
75            },
76            sqlite,
77            database: self,
78            statement_bytes: plan.statements.slots_bytes,
79            lookaside: memory.lookaside,
80            marker: marker::PhantomData,
81        };
82        Ok(topology::Plan::new(layout, open::Plan::new()))
83    }
84}
85
86impl<I: catalogs::Catalog> settings::Resource for Layout<'_, I> {
87    fn include_in(&self, needs: claim::Needs) -> Result<claim::Needs, errors::Claim> {
88        let timers = match self.settings.config.work.alarm() {
89            config::Alarm::Omit => Slots::ZERO,
90            config::Alarm::Reserve => Slots::fixed::<1>(),
91        };
92        needs.include(
93            claim::Claim::new(settings::Routes::EMPTY)
94                .schedule(demands::Schedule::new(Slots::ZERO, timers)),
95        )
96    }
97}
98
99impl<I: catalogs::Catalog> storage::Plan for Layout<'_, I> {
100    type Output<'p, 'd>
101        = local::State<'d, I>
102    where
103        Self: 'd,
104        'd: 'p;
105}
106
107impl<I: catalogs::Catalog> storage::Create for Layout<'_, I> {
108    type Error = runtime::Error;
109
110    fn try_build<'p, 'd>(
111        self,
112        mut context: storage::Context<'_, 'd>,
113    ) -> Result<Self::Output<'p, 'd>, Self::Error>
114    where
115        Self: 'd,
116        'd: 'p,
117    {
118        local::State::new(&mut context, self)
119    }
120}