flashdb_rs/
lib.rs

1#![cfg_attr(not(feature = "std"), no_std)]
2#![allow(non_upper_case_globals)]
3#![allow(non_camel_case_types)]
4#![allow(non_snake_case)]
5#![allow(clippy::all)]
6
7#![doc = include_str!("../README.md")]
8
9#[cfg(feature = "alloc")]
10extern crate alloc;
11
12pub mod error;
13pub mod kvdb;
14// pub mod time;
15pub mod tsdb;
16pub mod utils;
17
18use core::ffi::c_void;
19
20use embedded_storage::nor_flash::NorFlash;
21
22#[cfg(feature = "std")]
23pub mod storage;
24#[cfg(feature = "std")]
25pub use storage::StdStorage;
26
27pub use error::*;
28
29pub use kvdb::*;
30pub use tsdb::*;
31pub use utils::*;
32
33include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
34
35// 一个不安全的包装器,用于允许在 static 变量中使用包含裸指针的类型
36// C 库的 fdb_default_kv 结构体使用了裸指针,但我们知道在 static 上下文中它是只读且安全的
37pub struct SyncWrapper<T>(pub T);
38unsafe impl<T> Sync for SyncWrapper<T> {}
39
40/// 在编译时定义一组默认的键值对。
41///
42/// 这个宏会生成一个 `static` 的 `fdb_default_kv` 结构体,
43/// 可以被传递给 `KVDB::init` 方法。
44///
45/// # 示例
46///
47/// ```
48/// use flashdb_rs::define_default_kvs;
49/// define_default_kvs! {
50///     // 宏的名称将作为生成的 static 变量名
51///     MY_DEFAULT_KVS,
52///     // 键值对列表
53///     "version" => b"1.0.0",
54///     "boot_count" => b"\x00\x00\x00\x00", // 值可以是任意字节数组
55/// }
56///
57/// // 稍后在代码中使用
58/// // db.init("my_db", Some(&MY_DEFAULT_KVS))?;
59/// ```
60#[macro_export]
61macro_rules! define_default_kvs {
62    ($name:ident, $($key:expr => $value:expr),* $(,)?) => {
63        static KVS_ARRAY: &[$crate::SyncWrapper<$crate::fdb_default_kv_node>] = &[
64            $(
65                $crate::SyncWrapper($crate::fdb_default_kv_node {
66                    key: concat!($key, "\0").as_ptr() as *mut _,
67                    value: $value.as_ptr() as *mut _,
68                    value_len: $value.len(),
69                }),
70            )*
71        ];
72
73        #[allow(non_upper_case_globals)]
74        pub static $name: $crate::SyncWrapper<$crate::fdb_default_kv> = $crate::SyncWrapper($crate::fdb_default_kv {
75            kvs: KVS_ARRAY.as_ptr() as *mut $crate::fdb_default_kv_node,
76            num: KVS_ARRAY.len(),
77        });
78    };
79}
80
81pub trait RawHandle {
82    type Handle;
83
84    /// Care should be taken to use the returned ESP-IDF driver raw handle only while
85    /// the driver is still alive, so as to avoid use-after-free errors.
86    fn handle(&self) -> Self::Handle;
87}
88
89// 暴露给 C 的日志函数
90#[no_mangle]
91#[cfg(feature = "log")]
92pub extern "C" fn rust_log(message: *const core::ffi::c_char) {
93    let c_str = unsafe { core::ffi::CStr::from_ptr(message) };
94    if let Ok(message_str) = c_str.to_str() {
95        // 使用 Rust 的 log 宏输出(日志级别设为 INFO)
96        log::log!(log::Level::Info, "{message_str}");
97    }
98}
99
100#[doc(hidden)]
101#[repr(C)]
102pub struct FlashVTable {
103    pub read:
104        unsafe extern "C" fn(storage: *mut c_void, addr: u32, buf: *mut u8, size: usize) -> i32,
105    pub write:
106        unsafe extern "C" fn(storage: *mut c_void, addr: u32, buf: *const u8, size: usize) -> i32,
107    pub erase: unsafe extern "C" fn(storage: *mut c_void, addr: u32, size: usize) -> i32,
108}
109
110// 调度器结构体
111#[doc(hidden)]
112#[repr(C)]
113pub struct FlashDispatch {
114    pub vtable: FlashVTable,
115    pub instance: *mut c_void,
116}
117
118impl FlashDispatch {
119    pub fn new<T: NorFlash>() -> Self {
120        return Self {
121            vtable: FlashVTable {
122                read: vtable_read::<T>,
123                write: vtable_write::<T>,
124                erase: vtable_erase::<T>,
125            },
126            instance: core::ptr::null_mut(),
127        };
128    }
129}
130
131// --- VTable 的具体实现函数  ---
132unsafe extern "C" fn vtable_read<F: NorFlash>(
133    storage: *mut c_void,
134    addr: u32,
135    buf: *mut u8,
136    size: usize,
137) -> i32 {
138    let flash = &mut *(storage as *mut F);
139    let slice = core::slice::from_raw_parts_mut(buf, size);
140    match flash.read(addr, slice) {
141        Ok(_) => 0,
142        Err(_) => -1,
143    }
144}
145
146unsafe extern "C" fn vtable_write<F: NorFlash>(
147    storage: *mut c_void,
148    addr: u32,
149    buf: *const u8,
150    size: usize,
151) -> i32 {
152    let flash = &mut *(storage as *mut F);
153    let slice = core::slice::from_raw_parts(buf, size);
154    match flash.write(addr, slice) {
155        Ok(_) => 0,
156        Err(_) => -1,
157    }
158}
159
160unsafe extern "C" fn vtable_erase<F: NorFlash>(
161    storage: *mut c_void,
162    addr: u32,
163    size: usize,
164) -> i32 {
165    let flash = &mut *(storage as *mut F);
166    match flash.erase(addr, addr + size as u32) {
167        Ok(_) => 0,
168        Err(_) => -1,
169    }
170}
171
172#[no_mangle]
173pub unsafe extern "C" fn fdb_custom_read(
174    db: fdb_db_t,
175    addr: u32,
176    buf: *mut c_void,
177    size: usize,
178) -> fdb_err_t {
179    let dispatch = &*((*db).user_data as *const FlashDispatch);
180    let result = (dispatch.vtable.read)(dispatch.instance, addr, buf as *mut u8, size);
181    if result == 0 {
182        crate::fdb_err_t_FDB_NO_ERR
183    } else {
184        crate::fdb_err_t_FDB_READ_ERR
185    }
186}
187
188#[no_mangle]
189pub unsafe extern "C" fn fdb_custom_write(
190    db: fdb_db_t,
191    addr: u32,
192    buf: *const c_void,
193    size: usize,
194    _sync: bool,
195) -> fdb_err_t {
196    let dispatch = &*((*db).user_data as *const FlashDispatch);
197    let result = (dispatch.vtable.write)(dispatch.instance, addr, buf as *const u8, size);
198    if result == 0 {
199        crate::fdb_err_t_FDB_NO_ERR
200    } else {
201        crate::fdb_err_t_FDB_WRITE_ERR
202    }
203}
204
205#[no_mangle]
206pub unsafe extern "C" fn fdb_custom_erase(db: fdb_db_t, addr: u32, size: usize) -> fdb_err_t {
207    let dispatch = &*((*db).user_data as *const FlashDispatch);
208    let result = (dispatch.vtable.erase)(dispatch.instance, addr, size);
209    if result == 0 {
210        crate::fdb_err_t_FDB_NO_ERR
211    } else {
212        crate::fdb_err_t_FDB_ERASE_ERR
213    }
214}