| Crates.io | bitcoinleveldb-status |
| lib.rs | bitcoinleveldb-status |
| version | 0.1.19 |
| created_at | 2023-01-18 04:48:11.587322+00 |
| updated_at | 2025-12-01 16:56:53.859934+00 |
| description | C++-compatible LevelDB-style `Status` and `StatusCode` implementation used by bitcoin-rs for precise error classification, binary layout compatibility, and FFI with the Bitcoin Core LevelDB fork. |
| homepage | |
| repository | https://github.com/klebs6/bitcoin-rs |
| max_upload_size | |
| id | 761510 |
| size | 197,904 |
A small, C++-compatible Status implementation extracted from the Bitcoin Core LevelDB fork.
This crate mirrors the error-handling semantics of LevelDB's C++ Status type as used in Bitcoin Core, while providing an idiomatic Rust API. It is designed to be binary-layout compatible with the original implementation so that Rust code can interoperate cleanly with existing C/C++ LevelDB bindings and on-disk encodings.
The StatusCode enum is a direct translation of LevelDB's internal status codes:
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum StatusCode {
Ok, // 0
NotFound, // 1
Corruption, // 2
NotSupported, // 3
InvalidArgument,// 4
IOError, // 5
}
``
These codes are encoded as a single byte in the serialized `Status` layout, matching the C++ implementation (with the byte value at offset 4).
### Status
```rust
#[derive(Debug, Getters, Setters, Builder)]
#[getset(get = "pub", set = "pub")]
pub struct Status {
state: Option<Box<[u8]>>, // None => OK, Some => error with encoded payload
}
Semantics:
Status::ok() or Status::default() represent success and carry no payload (state: None).[0..4]: little-endian u32 length of the message[4]: the StatusCode as a raw u8[5..5+len]: UTF-8 error message data (typically from one or two Slice arguments, concatenated in the C++ implementation)This layout is intentionally low-level so that FFI and on-disk compatibility with Bitcoin's LevelDB fork can be maintained.
The crate provides move- and copy-like constructors/assignments modeled after the C++ interface, but in safe Rust form.
use bitcoinleveldb_status::{Status, StatusCode};
use bitcoinleveldb_slice::Slice; // or equivalent, depending on your stack
// OK status
let s_ok = Status::ok();
assert!(s_ok.is_ok());
// Error statuses
let msg = Slice::from_str("block index missing");
let st_not_found = Status::not_found(&msg, None);
let extra = Slice::from_str(" for hash abc123...");
let st_corrupt = Status::corruption(&msg, Some(&extra));
Available constructors (all static methods on Status):
Status::ok()Status::not_found(msg: &Slice, msg2: Option<&Slice>)Status::corruption(msg: &Slice, msg2: Option<&Slice>)Status::not_supported(msg: &Slice, msg2: Option<&Slice>)Status::invalid_argument(msg: &Slice, msg2: Option<&Slice>)Status::io_error(msg: &Slice, msg2: Option<&Slice>)Each method encodes the StatusCode plus the concatenated message into the internal state buffer.
if st_not_found.is_not_found() {
// handle missing key / file / record
}
match st_corrupt.code() {
StatusCode::Ok => { /* never for non-OK */ }
StatusCode::Corruption => { /* data corruption path */ }
StatusCode::IOError => { /* disk / fs error path */ }
_ => { /* other errors */ }
}
println!("status: {}", st_corrupt.to_string());
Provided predicates:
is_ok(&self) -> boolis_not_found(&self) -> boolis_corruption(&self) -> boolis_io_error(&self) -> boolis_not_supported_error(&self) -> boolis_invalid_argument(&self) -> boolPlus the low-level code extractor:
code(&self) -> StatusCodeThis crate emulates C++ copy/move semantics in a way that is convenient in FFI-heavy or ported codebases:
let original = Status::io_error(&Slice::from_str("fs full"), None);
// Copy-construction equivalent
let copy = Status::new_from_other_copy(&original);
assert_eq!(copy.to_string(), original.to_string());
// Move-construction equivalent
let original_moved = Status::new_from_other(original);
// `original` is now logically empty (OK) because its state was `take()`n.
// Copy assignment
let mut a = Status::ok();
let b = Status::invalid_argument(&Slice::from_str("height < 0"), None);
a.assign_from_other_copy(&b);
// Move assignment
let mut c = Status::ok();
let mut d = Status::not_supported(&Slice::from_str("compaction style"), None);
c.assign_from_other_move(&mut d);
Internally:
new_from_other(rhs: Status) -> Self takes ownership of rhs.state using Option::take, leaving rhs as OK.new_from_other_copy(rhs: &Status) -> Self deep-copies the internal buffer, preserving C++ copy constructor semantics.assign_from_other_copy(&mut self, rhs: &Status) -> &mut Status deep-copies unless both statuses share the same internal pointer.assign_from_other_move(&mut self, rhs: &mut Status) -> &mut Status drops any existing data and takes rhs.state.These helpers are primarily valuable when porting C++ LevelDB/Bitcoin code, where copy/move semantics are explicit in the original source.
let st = Status::not_found(&Slice::from_str("key"), None);
assert_eq!(st.to_string(), "NotFound: key");
let ok = Status::ok();
assert_eq!(ok.to_string(), "OK");
Format rules:
OK statuses stringify to exactly "OK".StatusCode:
NotFound: Corruption: Not implemented: (for NotSupported)Invalid argument: IO error: Several methods emit log lines through the log facade (or an equivalent logging backend), e.g.:
Status::default() logs when constructing an OK status.Drop for Status logs whether an OK or non-OK status is being dropped.code() logs a warning if it encounters an unknown numeric code.For deterministic behavior in production, configure a log-compatible backend (such as env_logger, flexi_logger, or a custom implementation) upstream in your application.
This crate is intended for:
leveldb::Status into Rust, this type allows nearly one-to-one structural translation, preserving behavior and string formats.Status. The internal [u8] layout is kept as a simple, contiguous representation compatible with C.If you are building a purely idiomatic Rust system, prefer using Result<T, E> with a structured error type instead. Status is particularly valuable where compatibility and fidelity to legacy behavior matter more than typical Rust ergonomics.
use bitcoinleveldb_status::Status;
use bitcoinleveldb_slice::Slice;
fn db_get(key: &Slice) -> (Status, Option<Vec<u8>>) {
// In a real implementation, this would call into LevelDB / Bitcoin's DB layer
if key.as_bytes().is_empty() {
return (
Status::invalid_argument(&Slice::from_str("empty key"), None),
None,
);
}
// pretend: key not present
let not_found_status = Status::not_found(&Slice::from_str("key not found"), None);
(not_found_status, None)
}
fn main() {
let key = Slice::from_str("");
let (st, value) = db_get(&key);
if !st.is_ok() {
eprintln!("db_get failed: {}", st.to_string());
return;
}
println!("value: {:?}", value.unwrap());
}
While the exact public API may evolve, this crate is conceptually constrained by the needs of the Bitcoin/LevelDB ecosystem:
Status encoding.If you require additional predicates or status codes, consider whether they exist in the upstream C++ implementation before extending the API, in order to avoid semantic drift.
bitcoin-rs repository license).This crate lives inside a larger ecosystem of Bitcoin-related Rust libraries. Please submit issues and pull requests to that repository, referencing bitcoinleveldb-status explicitly in your description.
By contributing, you agree to license your contributions under the MIT license of the project.