couchbase-lite 0.21.0

Ergonomic wrapper for couchbase-lite-core library
Documentation
use crate::{
    error::{Error, Result},
    ffi::{
        FLArray, FLArray_Count, FLArray_Get, FLArray_IsEmpty, FLDict, FLDict_Count, FLDict_Get,
        FLDict_IsEmpty, FLSlice, FLValue, FLValueType, FLValue_AsArray, FLValue_AsBool,
        FLValue_AsDict, FLValue_AsDouble, FLValue_AsFloat, FLValue_AsInt, FLValue_AsString,
        FLValue_AsUnsigned, FLValue_GetType, FLValue_IsDouble, FLValue_IsInteger,
        FLValue_IsUnsigned,
    },
};

#[derive(Debug, Clone, Copy)]
pub enum ValueRef<'a> {
    Null,
    Bool(bool),
    SignedInt(i64),
    UnsignedInt(u64),
    Float(f32),
    Double(f64),
    String(&'a str),
    Array(ValueRefArray),
    Dict(ValueRefDict),
}

impl ValueRef<'_> {
    #[inline]
    pub fn as_bool(&self) -> Result<bool> {
        FromValueRef::column_result(*self)
    }
    #[inline]
    pub fn as_i32(&self) -> Result<i32> {
        FromValueRef::column_result(*self)
    }
    #[inline]
    pub fn as_i64(&self) -> Result<i64> {
        FromValueRef::column_result(*self)
    }
    #[inline]
    pub fn as_u64(&self) -> Result<u64> {
        FromValueRef::column_result(*self)
    }
    #[inline]
    pub fn as_f32(&self) -> Result<f32> {
        FromValueRef::column_result(*self)
    }
    #[inline]
    pub fn as_f64(&self) -> Result<f64> {
        FromValueRef::column_result(*self)
    }
    #[inline]
    pub fn as_str(&self) -> Result<&str> {
        FromValueRef::column_result(*self)
    }
    #[inline]
    pub fn is_null(&self) -> bool {
        matches!(self, ValueRef::Null)
    }
    pub(crate) unsafe fn new(value: FLValue) -> Self {
        use FLValueType::*;
        match FLValue_GetType(value) {
            kFLUndefined | kFLNull => ValueRef::Null,
            kFLBoolean => ValueRef::Bool(FLValue_AsBool(value)),
            kFLNumber => {
                if FLValue_IsUnsigned(value) {
                    ValueRef::UnsignedInt(FLValue_AsUnsigned(value))
                } else if FLValue_IsInteger(value) {
                    ValueRef::SignedInt(FLValue_AsInt(value))
                } else if FLValue_IsDouble(value) {
                    ValueRef::Double(FLValue_AsDouble(value))
                } else {
                    ValueRef::Float(FLValue_AsFloat(value))
                }
            }
            kFLString => {
                let s: &str = FLValue_AsString(value).try_into().expect("not valid utf-8");
                ValueRef::String(s)
            }
            kFLArray => ValueRef::Array(ValueRefArray(FLValue_AsArray(value))),
            kFLDict => ValueRef::Dict(ValueRefDict(FLValue_AsDict(value))),
            kFLData => unimplemented!(),
        }
    }
}

#[derive(Debug, Clone, Copy)]
#[repr(transparent)]
pub struct ValueRefArray(FLArray);

impl ValueRefArray {
    #[inline]
    pub fn len(&self) -> u32 {
        unsafe { FLArray_Count(self.0) }
    }
    #[inline]
    pub fn is_empty(&self) -> bool {
        unsafe { FLArray_IsEmpty(self.0) }
    }
    pub(crate) unsafe fn get_raw(&self, idx: u32) -> FLValue {
        FLArray_Get(self.0, idx)
    }
    #[inline]
    pub fn get<'a>(&'a self, idx: u32) -> ValueRef<'a> {
        unsafe { ValueRef::new(self.get_raw(idx)) }
    }
}

#[derive(Debug, Clone, Copy)]
#[repr(transparent)]
pub struct ValueRefDict(FLDict);

impl ValueRefDict {
    #[inline]
    pub fn len(&self) -> u32 {
        unsafe { FLDict_Count(self.0) }
    }
    #[inline]
    pub fn is_empty(&self) -> bool {
        unsafe { FLDict_IsEmpty(self.0) }
    }
    pub(crate) unsafe fn get_raw(&self, key: FLSlice) -> FLValue {
        FLDict_Get(self.0, key)
    }
    #[inline]
    pub fn get<'a>(&'a self, key: FLSlice) -> ValueRef<'a> {
        unsafe { ValueRef::new(self.get_raw(key)) }
    }
}

pub trait FromValueRef<'a>: Sized {
    fn column_result(val: ValueRef<'a>) -> Result<Self>;
}

impl<'a> FromValueRef<'a> for bool {
    #[inline]
    fn column_result(val: ValueRef<'a>) -> Result<Self> {
        if let ValueRef::Bool(x) = val {
            Ok(x)
        } else {
            Err(Error::LogicError(
                format!("Wrong ValueRef type, expect Bool, got {val:?}").into(),
            ))
        }
    }
}

impl<'a> FromValueRef<'a> for &'a str {
    #[inline]
    fn column_result(val: ValueRef<'a>) -> Result<Self> {
        if let ValueRef::String(x) = val {
            Ok(x)
        } else {
            Err(Error::LogicError(
                format!("Wrong ValueRef type, expect String, got {val:?}").into(),
            ))
        }
    }
}

impl<'a> FromValueRef<'a> for u16 {
    fn column_result(val: ValueRef<'a>) -> Result<Self> {
        match val {
            ValueRef::SignedInt(x) => u16::try_from(x).map_err(|err| {
                Error::LogicError(
                    format!("ValueRef(Signed) {x} to u16 conversation error: {err}").into(),
                )
            }),
            ValueRef::UnsignedInt(x) => u16::try_from(x).map_err(|err| {
                Error::LogicError(
                    format!("ValueRef(Unsigned) {x} to u16 conversation error: {err}").into(),
                )
            }),
            _ => Err(Error::LogicError(
                format!("Wrong ValueRef type, expect SignedInt|UnsignedInt (u16) got {val:?}")
                    .into(),
            )),
        }
    }
}

impl<'a> FromValueRef<'a> for i32 {
    fn column_result(val: ValueRef<'a>) -> Result<Self> {
        match val {
            ValueRef::SignedInt(val) => i32::try_from(val).map_err(|err| {
                Error::LogicError(format!("i64->i32 conversation failure: {err}").into())
            }),
            ValueRef::UnsignedInt(val) => i32::try_from(val).map_err(|err| {
                Error::LogicError(format!("u64->i32 conversation failure: {err}").into())
            }),
            _ => Err(Error::LogicError(
                format!("Wrong ValueRef type, expect SignedInt|UnsignedInt (i32) got {val:?}")
                    .into(),
            )),
        }
    }
}

impl<'a> FromValueRef<'a> for u32 {
    fn column_result(val: ValueRef<'a>) -> Result<Self> {
        match val {
            ValueRef::SignedInt(x) => u32::try_from(x).map_err(|err| {
                Error::LogicError(
                    format!("ValueRef(Signed) {x} to u32 conversation error: {err}").into(),
                )
            }),
            ValueRef::UnsignedInt(x) => u32::try_from(x).map_err(|err| {
                Error::LogicError(
                    format!("ValueRef(Unsigned) {x} to u32 conversation error: {err}").into(),
                )
            }),
            _ => Err(Error::LogicError(
                format!("Wrong ValueRef type, expect SignedInt|UnsignedInt (u32) got {val:?}")
                    .into(),
            )),
        }
    }
}

impl<'a> FromValueRef<'a> for u64 {
    fn column_result(val: ValueRef<'a>) -> Result<Self> {
        match val {
            ValueRef::SignedInt(x) => u64::try_from(x).map_err(|err| {
                Error::LogicError(
                    format!("ValueRef(Signed) {x} to u32 conversation error: {err}").into(),
                )
            }),
            ValueRef::UnsignedInt(x) => Ok(x),
            _ => Err(Error::LogicError(
                format!("Wrong ValueRef type, expect SignedInt|UnsignedInt (u64) got {val:?}")
                    .into(),
            )),
        }
    }
}

impl<'a> FromValueRef<'a> for i64 {
    fn column_result(val: ValueRef<'a>) -> Result<Self> {
        match val {
            ValueRef::SignedInt(x) => Ok(x),
            ValueRef::UnsignedInt(x) => i64::try_from(x).map_err(|err| {
                Error::LogicError(
                    format!("ValueRef (UnsignedInt) to i64 conversation failed: {err}").into(),
                )
            }),
            _ => Err(Error::LogicError(
                format!("Wrong ValueRef type, expect SignedInt|UnsignedInt (i64) got {val:?}")
                    .into(),
            )),
        }
    }
}

impl<'a> FromValueRef<'a> for usize {
    fn column_result(val: ValueRef<'a>) -> Result<Self> {
        match val {
            ValueRef::SignedInt(x) => usize::try_from(x).map_err(|err| {
                Error::LogicError(
                    format!("ValueRef(Signed) {x} to usize conversation error: {err}").into(),
                )
            }),
            ValueRef::UnsignedInt(x) => usize::try_from(x).map_err(|err| {
                Error::LogicError(
                    format!("ValueRef(Unsigned) {x} to usize conversation error: {err}").into(),
                )
            }),
            _ => Err(Error::LogicError(
                format!("Wrong ValueRef type, expect SignedInt|UnsignedInt (usize) got {val:?}")
                    .into(),
            )),
        }
    }
}

impl<'a> FromValueRef<'a> for f32 {
    #[inline]
    fn column_result(val: ValueRef<'a>) -> Result<Self> {
        if let ValueRef::Float(x) = val {
            Ok(x)
        } else {
            Err(Error::LogicError(
                format!("Wrong ValueRef type, expect Float, got {val:?}").into(),
            ))
        }
    }
}

impl<'a> FromValueRef<'a> for f64 {
    #[inline]
    fn column_result(val: ValueRef<'a>) -> Result<Self> {
        match val {
            ValueRef::Float(x) => Ok(f64::from(x)),
            ValueRef::Double(x) => Ok(x),
            _ => Err(Error::LogicError(
                format!("Wrong ValueRef type, expect Float/Double, got {val:?}").into(),
            )),
        }
    }
}