use core::ptr;
extern crate alloc;
use alloc::sync::Arc;
use alloc::vec;
use embedded_svc::errors::Errors;
use embedded_svc::storage::Storage;
use esp_idf_sys::*;
use crate::nvs::*;
use crate::private::cstr::*;
enum EspNvsRef {
Default(Arc<EspDefaultNvs>),
Nvs(Arc<EspNvs>),
}
pub struct EspNvsStorage(EspNvsRef, nvs_handle_t);
impl EspNvsStorage {
pub fn new_default(
default_nvs: Arc<EspDefaultNvs>,
namespace: impl AsRef<str>,
read_write: bool,
) -> Result<Self, EspError> {
let c_namespace = CString::new(namespace.as_ref()).unwrap();
let mut handle: nvs_handle_t = 0;
esp!(unsafe {
nvs_open(
c_namespace.as_ptr(),
if read_write {
nvs_open_mode_t_NVS_READWRITE
} else {
nvs_open_mode_t_NVS_READONLY
},
&mut handle as *mut _,
)
})?;
Ok(Self(EspNvsRef::Default(default_nvs), handle))
}
pub fn new(
nvs: Arc<EspNvs>,
namespace: impl AsRef<str>,
read_write: bool,
) -> Result<Self, EspError> {
let c_namespace = CString::new(namespace.as_ref()).unwrap();
let mut handle: nvs_handle_t = 0;
esp!(unsafe {
nvs_open_from_partition(
nvs.0.as_ptr(),
c_namespace.as_ptr(),
if read_write {
nvs_open_mode_t_NVS_READWRITE
} else {
nvs_open_mode_t_NVS_READONLY
},
&mut handle as *mut _,
)
})?;
Ok(Self(EspNvsRef::Nvs(nvs), handle))
}
}
impl Drop for EspNvsStorage {
fn drop(&mut self) {
unsafe {
nvs_close(self.1);
}
}
}
impl Errors for EspNvsStorage {
type Error = EspError;
}
impl Storage for EspNvsStorage {
fn contains(&self, key: impl AsRef<str>) -> Result<bool, Self::Error> {
let c_key = CString::new(key.as_ref()).unwrap();
let mut dummy: u_int64_t = 0;
match unsafe { nvs_get_u64(self.1, c_key.as_ptr(), &mut dummy as *mut _) } {
ESP_ERR_NVS_NOT_FOUND => {
let mut len: size_t = 0;
match unsafe {
nvs_get_blob(self.1, c_key.as_ptr(), ptr::null_mut(), &mut len as *mut _)
} {
ESP_ERR_NVS_NOT_FOUND => Ok(false),
result => {
esp!(result)?;
Ok(true)
}
}
}
result => {
esp!(result)?;
Ok(true)
}
}
}
fn remove(&mut self, key: impl AsRef<str>) -> Result<bool, Self::Error> {
let c_key = CString::new(key.as_ref()).unwrap();
let result = unsafe { nvs_erase_key(self.1, c_key.as_ptr()) };
if result == ESP_ERR_NVS_NOT_FOUND as i32 {
Ok(false)
} else {
esp!(result)?;
esp!(unsafe { nvs_commit(self.1) })?;
Ok(true)
}
}
fn get_raw(&self, key: impl AsRef<str>) -> Result<Option<vec::Vec<u8>>, Self::Error> {
let c_key = CString::new(key.as_ref()).unwrap();
let mut value: u_int64_t = 0;
match unsafe { nvs_get_u64(self.1, c_key.as_ptr(), &mut value as *mut _) } {
ESP_ERR_NVS_NOT_FOUND => {
let mut len: size_t = 0;
match unsafe {
nvs_get_blob(self.1, c_key.as_ptr(), ptr::null_mut(), &mut len as *mut _)
} {
ESP_ERR_NVS_NOT_FOUND => Ok(None),
err => {
esp!(err)?;
let mut vec: vec::Vec<u8> = vec::Vec::with_capacity(len as usize);
esp!(unsafe {
nvs_get_blob(
self.1,
c_key.as_ptr(),
vec.as_mut_ptr() as *mut _,
&mut len as *mut _,
)
})?;
unsafe { vec.set_len(len as usize) };
Ok(Some(vec))
}
}
}
err => {
esp!(err)?;
let len: u8 = (value & 0xff) as u8;
value >>= 8;
let array: [u8; 7] = [
(value & 0xff) as u8,
((value >> 8) & 0xff) as u8,
((value >> 16) & 0xff) as u8,
((value >> 24) & 0xff) as u8,
((value >> 32) & 0xff) as u8,
((value >> 48) & 0xff) as u8,
((value >> 56) & 0xff) as u8,
];
Ok(Some(array[..len as usize].to_vec()))
}
}
}
fn put_raw(
&mut self,
key: impl AsRef<str>,
value: impl Into<vec::Vec<u8>>,
) -> Result<bool, Self::Error> {
let c_key = CString::new(key.as_ref()).unwrap();
let mut value = value.into();
let mut uvalue: u_int64_t = 0;
unsafe { nvs_erase_key(self.1, c_key.as_ptr()) };
if value.len() < 8 {
for v in value.iter().rev() {
uvalue <<= 8;
uvalue |= *v as u_int64_t;
}
uvalue <<= 8;
uvalue |= value.len() as u_int64_t;
esp!(unsafe { nvs_set_u64(self.1, c_key.as_ptr(), uvalue) })?;
} else {
esp!(unsafe {
nvs_set_blob(
self.1,
c_key.as_ptr(),
value.as_mut_ptr() as *mut _,
value.len() as u32,
)
})?;
}
esp!(unsafe { nvs_commit(self.1) })?;
Ok(true)
}
}