dex-blob-cache 0.3.1

Go-compatible DXBC blob cache for Dex SDKs
Documentation
// Copyright (c) 2026 Super Durable, Inc.
//
// Licensed under the Super Durable Source License 1.0.
// You may not use this file except in compliance with the License.
// See the LICENSE file in the repository root.
//
// SPDX-License-Identifier: LicenseRef-Super-Durable-1.0

use std::sync::{Condvar, Mutex};

use super::format::FileMetadata;

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum EntryStatus {
    Pending,
    Ready,
    Evicted,
}

#[derive(Debug)]
struct EntryState {
    status: EntryStatus,
    readers: usize,
}

#[derive(Debug)]
pub(crate) struct DiskEntry {
    pub(crate) metadata: FileMetadata,
    state: Mutex<EntryState>,
    readers_drained: Condvar,
}

impl DiskEntry {
    pub(crate) fn pending(metadata: FileMetadata) -> Self {
        Self {
            metadata,
            state: Mutex::new(EntryState {
                status: EntryStatus::Pending,
                readers: 0,
            }),
            readers_drained: Condvar::new(),
        }
    }

    pub(crate) fn ready(metadata: FileMetadata) -> Self {
        let entry = Self::pending(metadata);
        entry
            .state
            .lock()
            .expect("new disk entry mutex is not poisoned")
            .status = EntryStatus::Ready;
        entry
    }

    pub(crate) fn acquire_read(&self) -> Option<ReadLease<'_>> {
        let mut state = self.state.lock().expect("disk entry mutex is poisoned");
        if state.status != EntryStatus::Ready {
            return None;
        }
        state.readers += 1;
        Some(ReadLease { entry: self })
    }

    pub(crate) fn begin_eviction(&self) -> bool {
        let mut state = self.state.lock().expect("disk entry mutex is poisoned");
        if state.status == EntryStatus::Evicted {
            return false;
        }
        let was_ready = state.status == EntryStatus::Ready;
        state.status = EntryStatus::Evicted;
        while was_ready && state.readers != 0 {
            state = self
                .readers_drained
                .wait(state)
                .expect("disk entry mutex is poisoned");
        }
        was_ready
    }

    pub(crate) fn mark_ready(&self) -> bool {
        let mut state = self.state.lock().expect("disk entry mutex is poisoned");
        if state.status != EntryStatus::Pending {
            return false;
        }
        state.status = EntryStatus::Ready;
        true
    }

    pub(crate) fn restore_ready(&self) {
        self.state
            .lock()
            .expect("disk entry mutex is poisoned")
            .status = EntryStatus::Ready;
    }

    fn release_read(&self) {
        let mut state = self.state.lock().expect("disk entry mutex is poisoned");
        state.readers -= 1;
        if state.readers == 0 {
            self.readers_drained.notify_all();
        }
    }
}

pub(crate) struct ReadLease<'a> {
    entry: &'a DiskEntry,
}

impl Drop for ReadLease<'_> {
    fn drop(&mut self) {
        self.entry.release_read();
    }
}