Read() returns false for both a missing key and a deserialization
failure, making it impossible for callers to distinguish between
them.
This commits adds TryRead() returning a ReadStatus struct that
discriminates between:
- true: record found, value deserialized
- false: record not found
- DatabaseError: levelDB threw during record read
- DeserializationError: key present, value incompatible with
expected format
An err_msg field preserves the original exception message for
diagnostic purposes.
This also makes Read() a thin wrapper over TryRead() to keep
existing call sites unchanged.
Note:
Key serialization is the only operation that may throw in
TryRead(), as callers are expected to provide well-formed keys.
This is why this function is not noexcept.