pagedb 0.1.0-beta.6

Encrypted, portable, embedded page store with B+ tree and segment-file surfaces.
Documentation
use pagedb::{CommitId, CorruptionDetail, DbMode, Evictable, PagedbError, QuotaKind, RealmId};

#[test]
fn corruption_constructor_round_trips() {
    let err = PagedbError::corruption(CorruptionDetail::FooterUnverifiable {
        realm_id: RealmId::new([0u8; 16]),
        segment_id: [1u8; 16],
    });
    assert!(matches!(err, PagedbError::Corruption(_)));
    let _ = format!("{err}");
    let _ = format!("{err:?}");
}

#[test]
fn quota_constructor_round_trips() {
    let err = PagedbError::quota(RealmId::new([0u8; 16]), QuotaKind::SegmentBytes, 1024, 512);
    if let PagedbError::Quota {
        kind, used, limit, ..
    } = err
    {
        assert_eq!(kind, QuotaKind::SegmentBytes);
        assert_eq!(used, 1024);
        assert_eq!(limit, 512);
    } else {
        panic!("wrong variant");
    }
}

#[test]
fn io_error_from_conversion() {
    let io = std::io::Error::other("disk wobble");
    let err: PagedbError = io.into();
    assert!(matches!(err, PagedbError::Io(_)));
}

#[test]
fn device_exhaustion_is_classified_out_of_generic_io() {
    let full = std::io::Error::from(std::io::ErrorKind::StorageFull);
    let err: PagedbError = full.into();
    assert!(
        matches!(err, PagedbError::NoSpace),
        "a full device must not hide inside Io, got: {err:?}"
    );
}

#[test]
fn every_variant_displays() {
    let realm = RealmId::new([0u8; 16]);
    let cases: Vec<PagedbError> = vec![
        PagedbError::ChecksumFailure,
        PagedbError::corruption(CorruptionDetail::HeaderUnverifiable),
        PagedbError::structural_header_invalid("main.db", "magic"),
        PagedbError::page_chain_cycle("btree_descent", 41),
        PagedbError::leaf_sibling_mismatch(31, 31, None),
        PagedbError::BulkLoadNotMonotonic,
        PagedbError::vfs_contract_violated(
            "read_at",
            "reported more bytes than the caller requested",
        ),
        PagedbError::footer_framing_invalid("magic"),
        PagedbError::node_body_malformed("slot_directory"),
        PagedbError::node_kind_mismatch(Some(7), "leaf", "internal"),
        PagedbError::overflow_body_malformed("root.data_length"),
        PagedbError::journal_record_malformed("record.header"),
        PagedbError::snapshot_artifact_invalid("manifest.magic"),
        PagedbError::corruption(CorruptionDetail::ForeignSegment {
            realm_id: realm,
            name: "x".into(),
            segment_id: [0; 16],
            footer_parent_file_id: [1; 16],
            expected_parent_file_id: [2; 16],
        }),
        PagedbError::corruption(CorruptionDetail::SegmentMissing {
            realm_id: realm,
            name: "x".into(),
            segment_id: [0; 16],
        }),
        PagedbError::corruption(CorruptionDetail::StagingMissing {
            segment_id: [0; 16],
        }),
        PagedbError::corruption(CorruptionDetail::PageUnverifiable {
            realm_id: realm,
            segment_id: Some([0; 16]),
            page_id: 42,
            evictable: Some(Evictable::Replaceable),
        }),
        PagedbError::corruption(CorruptionDetail::ManifestUnverifiable {
            realm_id: realm,
            segment_id: [0; 16],
        }),
        PagedbError::quota(realm, QuotaKind::Pages, 1, 0),
        PagedbError::NoSpace,
        PagedbError::ReadOnly,
        PagedbError::WriterPresent,
        PagedbError::ReadersPresent,
        PagedbError::AlreadyOpen,
        PagedbError::AlreadyLocked,
        PagedbError::RestoredNotPromoted,
        PagedbError::wrong_mode("apply_incremental", DbMode::Follower, DbMode::Standalone),
        PagedbError::CommitGone {
            commit: CommitId::new(10),
            oldest_available: CommitId::new(20),
        },
        PagedbError::NotFound,
        PagedbError::AlreadyLinked,
        PagedbError::NotLinked,
        PagedbError::NameTooLong,
        PagedbError::IllegalPageKind,
        PagedbError::PayloadTooLarge,
        PagedbError::ManifestTooLarge,
        PagedbError::MmapViewQuotaExceeded {
            segment_bytes: 100,
            available_bytes: 50,
        },
        PagedbError::Aborted,
        PagedbError::ReadersPinningTruncatedRange,
        PagedbError::Unsupported,
    ];
    for c in &cases {
        let _ = format!("{c}");
        let _ = format!("{c:?}");
    }
}