fastly 0.8.8

Fastly Compute@Edge API
Documentation
//! Safe abstractions around the Object Store FFI.
use fastly_shared::{FastlyStatus, INVALID_BODY_HANDLE, INVALID_OBJECT_STORE_HANDLE};
use fastly_sys::fastly_object_store as sys;

use crate::handle::BodyHandle;

/// Errors that can arise during Object Store operations.
///
/// This type is marked as non-exhaustive because more variants will be added over time.
#[derive(Clone, Debug, Eq, PartialEq, thiserror::Error)]
#[non_exhaustive]
pub enum ObjectStoreError {
    /// The key provided for this operation was not valid.
    #[error("Invalid Object Store key")]
    InvalidKey,
    /// The Object Store handle provided for this operation was not valid.
    #[error("Invalid Object Store handle")]
    InvalidObjectStoreHandle,
    /// No Object Store by this name exists.
    #[error("Object Store {0:?} not found")]
    ObjectStoreNotFound(String),
    /// Some unexpected error occurred.
    #[error("Unexpected Object Store error: {0:?}")]
    Unexpected(FastlyStatus),
}

impl From<FastlyStatus> for ObjectStoreError {
    fn from(st: FastlyStatus) -> Self {
        ObjectStoreError::Unexpected(st)
    }
}

/// A handle to a key-value store that is open for lookups and inserting.
#[derive(Debug, Eq, Hash, PartialEq)]
#[repr(transparent)]
pub struct StoreHandle {
    handle: u32,
}

impl StoreHandle {
    /// Get the underlying representation of the handle.
    ///
    /// This should only be used when calling the raw ABI directly, and care should be taken not to
    /// reuse or alias handle values.
    pub fn as_u32(&self) -> u32 {
        self.handle
    }

    /// Open a handle to the Object Store with the given name.
    pub fn open(name: &str) -> Result<Option<StoreHandle>, ObjectStoreError> {
        let mut store_handle_out = INVALID_OBJECT_STORE_HANDLE;
        let status = unsafe { sys::open(name.as_ptr(), name.len(), &mut store_handle_out) };
        status.result().map_err(|st| match st {
            FastlyStatus::INVAL => ObjectStoreError::ObjectStoreNotFound(name.to_owned()),
            _ => st.into(),
        })?;
        if store_handle_out == INVALID_OBJECT_STORE_HANDLE {
            Ok(None)
        } else {
            Ok(Some(StoreHandle {
                handle: store_handle_out,
            }))
        }
    }

    /// Look up a value in the Object Store.
    ///
    /// Returns `Ok(Some(BodyHandle))` if a value is found, and `Ok(None)` if the key was not
    /// found or is expired.
    pub fn lookup(&self, key: impl AsRef<[u8]>) -> Result<Option<BodyHandle>, ObjectStoreError> {
        let mut body_handle_out = INVALID_BODY_HANDLE;
        let key = key.as_ref();
        let status =
            unsafe { sys::lookup(self.as_u32(), key.as_ptr(), key.len(), &mut body_handle_out) };
        status.result().map_err(|st| match st {
            FastlyStatus::BADF => ObjectStoreError::InvalidObjectStoreHandle,
            FastlyStatus::INVAL => ObjectStoreError::InvalidKey,
            _ => st.into(),
        })?;
        if body_handle_out == INVALID_BODY_HANDLE {
            Ok(None)
        } else {
            Ok(Some(unsafe { BodyHandle::from_u32(body_handle_out) }))
        }
    }

    /// Insert a value into the Object Store.
    ///
    /// If the Object Store already contains a value for this key, it will be overwritten.
    pub fn insert(
        &mut self,
        key: impl AsRef<str>,
        value: BodyHandle,
    ) -> Result<(), ObjectStoreError> {
        let key = key.as_ref();
        let status =
            unsafe { sys::insert(self.as_u32(), key.as_ptr(), key.len(), value.into_u32()) };
        status.result().map_err(|st| match st {
            FastlyStatus::BADF => ObjectStoreError::InvalidObjectStoreHandle,
            FastlyStatus::INVAL => ObjectStoreError::InvalidKey,
            _ => st.into(),
        })?;
        Ok(())
    }
}