MAJOR error rewrite to track file/line

This commit is contained in:
Mike Dilger 2024-02-15 17:03:40 +13:00
parent 612ddb0ab3
commit fef0d7a542
17 changed files with 352 additions and 152 deletions

1
Cargo.lock generated
View File

@ -152,7 +152,6 @@ dependencies = [
"secp256k1", "secp256k1",
"serde", "serde",
"tempfile", "tempfile",
"thiserror",
"tokio", "tokio",
"tokio-rustls", "tokio-rustls",
] ]

View File

@ -20,7 +20,6 @@ ron = "0.8"
rustls-pemfile = "1.0" rustls-pemfile = "1.0"
secp256k1 = { version = "0.28", features = [ "hashes", "global-context", "rand-std" ] } secp256k1 = { version = "0.28", features = [ "hashes", "global-context", "rand-std" ] }
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
thiserror = "1.0"
tokio = { version = "1", features = [ "full" ] } tokio = { version = "1", features = [ "full" ] }
tokio-rustls = "0.24" tokio-rustls = "0.24"

View File

@ -1,112 +1,308 @@
use thiserror::Error; use std::error::Error as StdError;
use std::panic::Location;
#[derive(Debug)]
pub struct Error {
pub inner: ChorusError,
location: &'static Location<'static>,
}
impl StdError for Error {
fn source(&self) -> Option<&(dyn StdError + 'static)> {
Some(&self.inner)
}
}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}, {}", self.inner, self.location)
}
}
/// Errors that can occur in the chorus crate /// Errors that can occur in the chorus crate
#[derive(Error, Debug)] #[derive(Debug)]
pub enum Error { pub enum ChorusError {
// Bad event id // Bad event id
#[error("Bad event id, does not match hash")]
BadEventId, BadEventId,
// Bad hex input // Bad hex input
#[error("Bad hex input")]
BadHexInput, BadHexInput,
// Output buffer too small // Output buffer too small
#[error("Output buffer too small")]
BufferTooSmall, BufferTooSmall,
// Channel Recv // Channel Recv
#[error("Channel receive: {0}")] ChannelRecv(tokio::sync::broadcast::error::RecvError),
ChannelRecv(#[from] tokio::sync::broadcast::error::RecvError),
// Channel Send // Channel Send
#[error("Channel send: {0}")] ChannelSend(tokio::sync::broadcast::error::SendError<usize>),
ChannelSend(#[from] tokio::sync::broadcast::error::SendError<usize>),
// Config // Config
#[error("Config: {0}")] Config(ron::error::SpannedError),
Config(#[from] ron::error::SpannedError),
// Crypto // Crypto
#[error("Crypto: {0}")] Crypto(secp256k1::Error),
Crypto(#[from] secp256k1::Error),
// Duplicate event // Duplicate event
#[error("Duplicate")]
Duplicate, Duplicate,
// End of Input // End of Input
#[error("End of input")]
EndOfInput, EndOfInput,
// Http // Http
#[error("HTTP: {0}")] Http(hyper::http::Error),
Http(#[from] hyper::http::Error),
// Hyper // Hyper
#[error("Hyper: {0}")] Hyper(hyper::Error),
Hyper(#[from] hyper::Error),
// I/O Error // I/O
#[error("I/O: {0}")] Io(std::io::Error),
Io(#[from] std::io::Error),
// JSON Bad (general) // JSON Bad (general)
#[error("JSON bad: {0} at position {1}")]
JsonBad(&'static str, usize), JsonBad(&'static str, usize),
// JSON Bad Character // JSON Bad Character
#[error("JSON bad character: {0} at position {1}, {2} was expected")]
JsonBadCharacter(char, usize, char), JsonBadCharacter(char, usize, char),
// JSON Bad Event // JSON Bad Event
#[error("JSON bad event: {0} at position {1}")]
JsonBadEvent(&'static str, usize), JsonBadEvent(&'static str, usize),
// JSON Bad Filter // JSON Bad Filter
#[error("JSON bad filter: {0} at position {1}")]
JsonBadFilter(&'static str, usize), JsonBadFilter(&'static str, usize),
// JSON Bad String Character // JSON Bad String Character
#[error("JSON string bad character: codepoint {0}")]
JsonBadStringChar(u32), JsonBadStringChar(u32),
// JSON Escape // JSON Escape
#[error("JSON string escape error")]
JsonEscape, JsonEscape,
// JSON Escape Surrogate // JSON Escape Surrogate
#[error("JSON string escape surrogate (ancient style) is not supported")]
JsonEscapeSurrogate, JsonEscapeSurrogate,
// LMDB // LMDB
#[error("LMDB: {0}")] Lmdb(heed::Error),
Lmdb(#[from] heed::Error),
#[error("Private Key Not Found")] // No private key
NoPrivateKey, NoPrivateKey,
// Rustls // Rustls
#[error("TLS: {0}")] Rustls(tokio_rustls::rustls::Error),
Rustls(#[from] tokio_rustls::rustls::Error),
// Tunstenite // Tungstenite
#[error("Websocket: {0}")] Tungstenite(hyper_tungstenite::tungstenite::error::Error),
Tungstenite(#[from] hyper_tungstenite::tungstenite::error::Error),
// Filter is underspecified // Filter is underspecified
#[error("Filter is underspecified. Scrapers are not allowed")]
Scraper, Scraper,
// UTF-8 // UTF-8
#[error("UTF-8: {0}")] Utf8(std::str::Utf8Error),
Utf8(#[from] std::str::Utf8Error),
// UTF-8 // UTF-8
#[error("UTF-8 error")]
Utf8Error, Utf8Error,
// Tunstenite Protocol // Tungstenite Protocol
#[error("Websocket Protocol: {0}")] WebsocketProtocol(hyper_tungstenite::tungstenite::error::ProtocolError),
WebsocketProtocol(#[from] hyper_tungstenite::tungstenite::error::ProtocolError), }
impl std::fmt::Display for ChorusError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ChorusError::BadEventId => write!(f, "Bad event id, does not match hash"),
ChorusError::BadHexInput => write!(f, "Bad hex input"),
ChorusError::BufferTooSmall => write!(f, "Output buffer too small"),
ChorusError::ChannelRecv(e) => write!(f, "{e}"),
ChorusError::ChannelSend(e) => write!(f, "{e}"),
ChorusError::Config(e) => write!(f, "{e}"),
ChorusError::Crypto(e) => write!(f, "{e}"),
ChorusError::Duplicate => write!(f, "Duplicate"),
ChorusError::EndOfInput => write!(f, "End of input"),
ChorusError::Http(e) => write!(f, "{e}"),
ChorusError::Hyper(e) => write!(f, "{e}"),
ChorusError::Io(e) => write!(f, "{e}"),
ChorusError::JsonBad(err, pos) => write!(f, "JSON bad: {err} at position {pos}"),
ChorusError::JsonBadCharacter(c, pos, ec) => write!(
f,
"JSON bad character: {c} at position {pos}, {ec} was expected"
),
ChorusError::JsonBadEvent(err, pos) => {
write!(f, "JSON bad event: {err} at position {pos}")
}
ChorusError::JsonBadFilter(err, pos) => {
write!(f, "JSON bad filter: {err} at position {pos}")
}
ChorusError::JsonBadStringChar(ch) => {
write!(f, "JSON string bad character: codepoint {ch}")
}
ChorusError::JsonEscape => write!(f, "JSON string escape error"),
ChorusError::JsonEscapeSurrogate => write!(
f,
"JSON string escape surrogate (ancient style) is not supported"
),
ChorusError::Lmdb(e) => write!(f, "{e}"),
ChorusError::NoPrivateKey => write!(f, "Private Key Not Found"),
ChorusError::Rustls(e) => write!(f, "{e}"),
ChorusError::Tungstenite(e) => write!(f, "{e}"),
ChorusError::Scraper => write!(f, "Filter is underspecified. Scrapers are not allowed"),
ChorusError::Utf8(e) => write!(f, "{e}"),
ChorusError::Utf8Error => write!(f, "UTF-8 error"),
ChorusError::WebsocketProtocol(e) => write!(f, "{e}"),
}
}
}
impl StdError for ChorusError {
fn source(&self) -> Option<&(dyn StdError + 'static)> {
match self {
ChorusError::ChannelRecv(e) => Some(e),
ChorusError::ChannelSend(e) => Some(e),
ChorusError::Config(e) => Some(e),
ChorusError::Crypto(e) => Some(e),
ChorusError::Http(e) => Some(e),
ChorusError::Hyper(e) => Some(e),
ChorusError::Io(e) => Some(e),
ChorusError::Lmdb(e) => Some(e),
ChorusError::Rustls(e) => Some(e),
ChorusError::Tungstenite(e) => Some(e),
ChorusError::Utf8(e) => Some(e),
ChorusError::WebsocketProtocol(e) => Some(e),
_ => None,
}
}
}
// Note: we impl Into because our typical pattern is ChorusError::Variant.into()
// when we tried implementing From, the location was deep in rust code's
// blanket into implementation, which wasn't the line number we wanted.
//
// As for converting other error types (below) the try! macro uses From so it
// is correct.
#[allow(clippy::from_over_into)]
impl Into<Error> for ChorusError {
#[track_caller]
fn into(self) -> Error {
Error {
inner: self,
location: std::panic::Location::caller(),
}
}
}
impl From<tokio::sync::broadcast::error::RecvError> for Error {
#[track_caller]
fn from(err: tokio::sync::broadcast::error::RecvError) -> Self {
Error {
inner: ChorusError::ChannelRecv(err),
location: std::panic::Location::caller(),
}
}
}
impl From<tokio::sync::broadcast::error::SendError<usize>> for Error {
#[track_caller]
fn from(err: tokio::sync::broadcast::error::SendError<usize>) -> Self {
Error {
inner: ChorusError::ChannelSend(err),
location: std::panic::Location::caller(),
}
}
}
impl From<ron::error::SpannedError> for Error {
#[track_caller]
fn from(err: ron::error::SpannedError) -> Self {
Error {
inner: ChorusError::Config(err),
location: std::panic::Location::caller(),
}
}
}
impl From<secp256k1::Error> for Error {
#[track_caller]
fn from(err: secp256k1::Error) -> Self {
Error {
inner: ChorusError::Crypto(err),
location: std::panic::Location::caller(),
}
}
}
impl From<hyper::http::Error> for Error {
#[track_caller]
fn from(err: hyper::http::Error) -> Self {
Error {
inner: ChorusError::Http(err),
location: std::panic::Location::caller(),
}
}
}
impl From<hyper::Error> for Error {
#[track_caller]
fn from(err: hyper::Error) -> Self {
Error {
inner: ChorusError::Hyper(err),
location: std::panic::Location::caller(),
}
}
}
impl From<std::io::Error> for Error {
#[track_caller]
fn from(err: std::io::Error) -> Self {
Error {
inner: ChorusError::Io(err),
location: std::panic::Location::caller(),
}
}
}
impl From<heed::Error> for Error {
#[track_caller]
fn from(err: heed::Error) -> Self {
Error {
inner: ChorusError::Lmdb(err),
location: std::panic::Location::caller(),
}
}
}
impl From<tokio_rustls::rustls::Error> for Error {
#[track_caller]
fn from(err: tokio_rustls::rustls::Error) -> Self {
Error {
inner: ChorusError::Rustls(err),
location: std::panic::Location::caller(),
}
}
}
impl From<hyper_tungstenite::tungstenite::error::Error> for Error {
#[track_caller]
fn from(err: hyper_tungstenite::tungstenite::error::Error) -> Self {
Error {
inner: ChorusError::Tungstenite(err),
location: std::panic::Location::caller(),
}
}
}
impl From<std::str::Utf8Error> for Error {
#[track_caller]
fn from(err: std::str::Utf8Error) -> Self {
Error {
inner: ChorusError::Utf8(err),
location: std::panic::Location::caller(),
}
}
}
impl From<hyper_tungstenite::tungstenite::error::ProtocolError> for Error {
#[track_caller]
fn from(err: hyper_tungstenite::tungstenite::error::ProtocolError) -> Self {
Error {
inner: ChorusError::WebsocketProtocol(err),
location: std::panic::Location::caller(),
}
}
} }

View File

@ -19,7 +19,7 @@ macro_rules! write_hex {
($input:expr, $output:expr, $bytelen:expr) => {{ ($input:expr, $output:expr, $bytelen:expr) => {{
assert_eq!($input.len(), $bytelen); assert_eq!($input.len(), $bytelen);
if $output.len() != $bytelen * 2 { if $output.len() != $bytelen * 2 {
Err(Error::BufferTooSmall) Err(crate::error::ChorusError::BufferTooSmall.into())
} else { } else {
for (i, byte) in $input.iter().enumerate() { for (i, byte) in $input.iter().enumerate() {
$output[i * 2] = crate::HEX_CHARS[((byte & 0xF0) >> 4) as usize]; $output[i * 2] = crate::HEX_CHARS[((byte & 0xF0) >> 4) as usize];
@ -34,17 +34,17 @@ macro_rules! read_hex {
($input:expr, $output:expr, $bytelen:expr) => {{ ($input:expr, $output:expr, $bytelen:expr) => {{
assert_eq!($output.len(), $bytelen); assert_eq!($output.len(), $bytelen);
if $input.len() != $bytelen * 2 { if $input.len() != $bytelen * 2 {
Err(Error::EndOfInput) Err(Into::<crate::error::Error>::into(crate::error::ChorusError::EndOfInput))
} else { } else {
let mut i = 0; let mut i = 0;
loop { loop {
let high = crate::HEX_INVERSE[$input[i * 2] as usize]; let high = crate::HEX_INVERSE[$input[i * 2] as usize];
if high == 255 { if high == 255 {
break Err(Error::BadHexInput); break Err(crate::error::ChorusError::BadHexInput.into());
} }
let low = crate::HEX_INVERSE[$input[i * 2 + 1] as usize]; let low = crate::HEX_INVERSE[$input[i * 2 + 1] as usize];
if low == 255 { if low == 255 {
break Err(Error::BadHexInput); break Err(crate::error::ChorusError::BadHexInput.into());
} }
$output[i] = high * 16 + low; $output[i] = high * 16 + low;
i += 1; i += 1;

View File

@ -11,7 +11,7 @@ pub mod types;
pub mod web; pub mod web;
use crate::config::{Config, FriendlyConfig}; use crate::config::{Config, FriendlyConfig};
use crate::error::Error; use crate::error::{ChorusError, Error};
use crate::globals::GLOBALS; use crate::globals::GLOBALS;
use crate::reply::NostrReply; use crate::reply::NostrReply;
use crate::store::Store; use crate::store::Store;
@ -172,13 +172,15 @@ async fn handle_http_request(
// Handle the websocket // Handle the websocket
if let Err(e) = ws_service.handle_websocket_stream().await { if let Err(e) = ws_service.handle_websocket_stream().await {
match e { if matches!(
Error::Tungstenite(tungstenite::error::Error::Protocol( e.inner,
tungstenite::error::ProtocolError::ResetWithoutClosingHandshake, ChorusError::Tungstenite(tungstenite::error::Error::Protocol(
)) => { tungstenite::error::ProtocolError::ResetWithoutClosingHandshake
// swallow ))
} ) {
e => log::error!("{}: {}", peer, e), // Swallow the boring error
} else {
log::error!("{}: {}", peer, e);
} }
} }

View File

@ -1,4 +1,4 @@
use crate::error::Error; use crate::error::{ChorusError, Error};
use crate::globals::GLOBALS; use crate::globals::GLOBALS;
use crate::reply::NostrReply; use crate::reply::NostrReply;
use crate::types::parse::json_escape::json_unescape; use crate::types::parse::json_escape::json_unescape;
@ -140,8 +140,13 @@ impl WebSocketService {
GLOBALS.new_events.send(offset)?; // advertise the new event GLOBALS.new_events.send(offset)?; // advertise the new event
NostrReply::Ok(event.id(), true, "".to_owned()) NostrReply::Ok(event.id(), true, "".to_owned())
} }
Err(Error::Duplicate) => NostrReply::Ok(event.id(), true, "duplicate:".to_owned()), Err(e) => {
Err(e) => NostrReply::Ok(event.id(), false, format!("{e}")), if matches!(e.inner, ChorusError::Duplicate) {
NostrReply::Ok(event.id(), true, "duplicate:".to_owned())
} else {
NostrReply::Ok(event.id(), false, format!("{e}"))
}
}
}; };
self.websocket.send(Message::text(reply.as_json())).await?; self.websocket.send(Message::text(reply.as_json())).await?;

View File

@ -1,7 +1,7 @@
pub mod event_store; pub mod event_store;
pub use event_store::EventStore; pub use event_store::EventStore;
use crate::error::Error; use crate::error::{ChorusError, Error};
use crate::types::{Event, Filter, Id, Kind, Pubkey, Time}; use crate::types::{Event, Filter, Id, Kind, Pubkey, Time};
use heed::types::{OwnedType, UnalignedSlice}; use heed::types::{OwnedType, UnalignedSlice};
use heed::{Database, Env, EnvFlags, EnvOpenOptions}; use heed::{Database, Env, EnvFlags, EnvOpenOptions};
@ -133,7 +133,7 @@ impl Store {
txn.commit()?; txn.commit()?;
} else { } else {
return Err(Error::Duplicate); return Err(ChorusError::Duplicate.into());
} }
Ok(offset) Ok(offset)
@ -294,7 +294,7 @@ impl Store {
} }
} }
} else { } else {
return Err(Error::Scraper); return Err(ChorusError::Scraper.into());
} }
Ok(output) Ok(output)

View File

@ -1,5 +1,5 @@
use crate::config::Config; use crate::config::Config;
use crate::error::Error; use crate::error::{ChorusError, Error};
use rustls::{Certificate, PrivateKey}; use rustls::{Certificate, PrivateKey};
use std::fs::File; use std::fs::File;
use std::io::BufReader; use std::io::BufReader;
@ -25,7 +25,7 @@ pub fn tls_acceptor(config: &Config) -> Result<TlsAcceptor, Error> {
let key = match keys.pop() { let key = match keys.pop() {
Some(k) => k, Some(k) => k,
None => return Err(Error::NoPrivateKey), None => return Err(ChorusError::NoPrivateKey.into()),
}; };
let tls_config = rustls::ServerConfig::builder() let tls_config = rustls::ServerConfig::builder()

View File

@ -1,5 +1,5 @@
use crate::error::{ChorusError, Error};
use crate::types::parse::json_parse::*; use crate::types::parse::json_parse::*;
use crate::Error;
/// Parses a JSON event from the `input` buffer. Places the parsed event into the `output` buffer. /// Parses a JSON event from the `input` buffer. Places the parsed event into the `output` buffer.
/// Returns the count of consumed bytes and output bytes /// Returns the count of consumed bytes and output bytes
@ -7,7 +7,7 @@ pub fn parse_json_event(input: &[u8], output: &mut [u8]) -> Result<(usize, usize
// Minimum-sized JSON event is 204 characters long // Minimum-sized JSON event is 204 characters long
// NOTE: 152 is the minimum binary event // NOTE: 152 is the minimum binary event
if input.len() < 204 { if input.len() < 204 {
return Err(Error::JsonBadEvent("Too Short", 0)); return Err(ChorusError::JsonBadEvent("Too Short", 0).into());
} }
// This tracks where we are currently looking in the input as we scan forward. // This tracks where we are currently looking in the input as we scan forward.
@ -49,12 +49,12 @@ pub fn parse_json_event(input: &[u8], output: &mut [u8]) -> Result<(usize, usize
// field and value: kind":1 // field and value: kind":1
// This allows us to skip length tests below that are shorter than inpos+7 // This allows us to skip length tests below that are shorter than inpos+7
if inpos + 7 > input.len() { if inpos + 7 > input.len() {
return Err(Error::JsonBadEvent("Too Short or Missing Fields", inpos)); return Err(ChorusError::JsonBadEvent("Too Short or Missing Fields", inpos).into());
} }
if &input[inpos..inpos + 3] == b"id\"" { if &input[inpos..inpos + 3] == b"id\"" {
if complete & HAVE_ID == HAVE_ID { if complete & HAVE_ID == HAVE_ID {
return Err(Error::JsonBadEvent("Duplicate id field", inpos)); return Err(ChorusError::JsonBadEvent("Duplicate id field", inpos).into());
} }
inpos += 3; inpos += 3;
eat_colon_with_whitespace(input, &mut inpos)?; eat_colon_with_whitespace(input, &mut inpos)?;
@ -62,7 +62,7 @@ pub fn parse_json_event(input: &[u8], output: &mut [u8]) -> Result<(usize, usize
complete |= HAVE_ID; complete |= HAVE_ID;
} else if &input[inpos..inpos + 4] == b"sig\"" { } else if &input[inpos..inpos + 4] == b"sig\"" {
if complete & HAVE_SIG == HAVE_SIG { if complete & HAVE_SIG == HAVE_SIG {
return Err(Error::JsonBadEvent("Duplicate sig field", inpos)); return Err(ChorusError::JsonBadEvent("Duplicate sig field", inpos).into());
} }
inpos += 4; inpos += 4;
eat_colon_with_whitespace(input, &mut inpos)?; eat_colon_with_whitespace(input, &mut inpos)?;
@ -70,7 +70,7 @@ pub fn parse_json_event(input: &[u8], output: &mut [u8]) -> Result<(usize, usize
complete |= HAVE_SIG; complete |= HAVE_SIG;
} else if &input[inpos..inpos + 5] == b"kind\"" { } else if &input[inpos..inpos + 5] == b"kind\"" {
if complete & HAVE_KIND == HAVE_KIND { if complete & HAVE_KIND == HAVE_KIND {
return Err(Error::JsonBadEvent("Duplicate kind field", inpos)); return Err(ChorusError::JsonBadEvent("Duplicate kind field", inpos).into());
} }
inpos += 5; inpos += 5;
eat_colon_with_whitespace(input, &mut inpos)?; eat_colon_with_whitespace(input, &mut inpos)?;
@ -79,7 +79,7 @@ pub fn parse_json_event(input: &[u8], output: &mut [u8]) -> Result<(usize, usize
complete |= HAVE_KIND; complete |= HAVE_KIND;
} else if &input[inpos..inpos + 5] == b"tags\"" { } else if &input[inpos..inpos + 5] == b"tags\"" {
if complete & HAVE_TAGS == HAVE_TAGS { if complete & HAVE_TAGS == HAVE_TAGS {
return Err(Error::JsonBadEvent("Duplicate tags field", inpos)); return Err(ChorusError::JsonBadEvent("Duplicate tags field", inpos).into());
} }
inpos += 5; inpos += 5;
eat_colon_with_whitespace(input, &mut inpos)?; eat_colon_with_whitespace(input, &mut inpos)?;
@ -93,7 +93,7 @@ pub fn parse_json_event(input: &[u8], output: &mut [u8]) -> Result<(usize, usize
} }
} else if &input[inpos..inpos + 7] == b"pubkey\"" { } else if &input[inpos..inpos + 7] == b"pubkey\"" {
if complete & HAVE_PUBKEY == HAVE_PUBKEY { if complete & HAVE_PUBKEY == HAVE_PUBKEY {
return Err(Error::JsonBadEvent("Duplicate pubkey field", inpos)); return Err(ChorusError::JsonBadEvent("Duplicate pubkey field", inpos).into());
} }
inpos += 7; inpos += 7;
eat_colon_with_whitespace(input, &mut inpos)?; eat_colon_with_whitespace(input, &mut inpos)?;
@ -101,7 +101,7 @@ pub fn parse_json_event(input: &[u8], output: &mut [u8]) -> Result<(usize, usize
complete |= HAVE_PUBKEY; complete |= HAVE_PUBKEY;
} else if inpos + 8 <= input.len() && &input[inpos..inpos + 8] == b"content\"" { } else if inpos + 8 <= input.len() && &input[inpos..inpos + 8] == b"content\"" {
if complete & HAVE_CONTENT == HAVE_CONTENT { if complete & HAVE_CONTENT == HAVE_CONTENT {
return Err(Error::JsonBadEvent("Duplicate pubkey field", inpos)); return Err(ChorusError::JsonBadEvent("Duplicate pubkey field", inpos).into());
} }
inpos += 8; inpos += 8;
eat_colon_with_whitespace(input, &mut inpos)?; eat_colon_with_whitespace(input, &mut inpos)?;
@ -119,7 +119,7 @@ pub fn parse_json_event(input: &[u8], output: &mut [u8]) -> Result<(usize, usize
} }
} else if inpos + 11 <= input.len() && &input[inpos..inpos + 11] == b"created_at\"" { } else if inpos + 11 <= input.len() && &input[inpos..inpos + 11] == b"created_at\"" {
if complete & HAVE_CREATED_AT == HAVE_CREATED_AT { if complete & HAVE_CREATED_AT == HAVE_CREATED_AT {
return Err(Error::JsonBadEvent("Duplicate created_at field", inpos)); return Err(ChorusError::JsonBadEvent("Duplicate created_at field", inpos).into());
} }
inpos += 11; inpos += 11;
eat_colon_with_whitespace(input, &mut inpos)?; eat_colon_with_whitespace(input, &mut inpos)?;
@ -142,7 +142,7 @@ pub fn parse_json_event(input: &[u8], output: &mut [u8]) -> Result<(usize, usize
u32::from_ne_bytes(output[0..4].try_into().unwrap()) as usize, u32::from_ne_bytes(output[0..4].try_into().unwrap()) as usize,
)) ))
} else { } else {
Err(Error::JsonBadEvent("Missing Fields", inpos)) Err(ChorusError::JsonBadEvent("Missing Fields", inpos).into())
} }
} }

View File

@ -1,5 +1,5 @@
use super::{Id, Kind, Pubkey, Sig, Tags, Time}; use super::{Id, Kind, Pubkey, Sig, Tags, Time};
use crate::Error; use crate::error::{ChorusError, Error};
use std::fmt; use std::fmt;
mod json_event; mod json_event;
@ -35,11 +35,11 @@ impl<'a> Event<'a> {
// this marks off the slice of bytes that represent an event from a potentially longer input // this marks off the slice of bytes that represent an event from a potentially longer input
pub fn delineate(input: &'a [u8]) -> Result<Event<'a>, Error> { pub fn delineate(input: &'a [u8]) -> Result<Event<'a>, Error> {
if input.len() < 144 + 4 + 4 { if input.len() < 144 + 4 + 4 {
return Err(Error::EndOfInput); return Err(ChorusError::EndOfInput.into());
} }
let len = parse_u32!(input, 0) as usize; let len = parse_u32!(input, 0) as usize;
if input.len() < len { if input.len() < len {
return Err(Error::EndOfInput); return Err(ChorusError::EndOfInput.into());
} }
Ok(Event(&input[0..len])) Ok(Event(&input[0..len]))
} }
@ -47,7 +47,7 @@ impl<'a> Event<'a> {
// This copies // This copies
pub fn copy(&self, output: &mut [u8]) -> Result<(), Error> { pub fn copy(&self, output: &mut [u8]) -> Result<(), Error> {
if output.len() < self.0.len() { if output.len() < self.0.len() {
return Err(Error::BufferTooSmall); return Err(ChorusError::BufferTooSmall.into());
} }
output[..self.0.len()].copy_from_slice(self.0); output[..self.0.len()].copy_from_slice(self.0);
Ok(()) Ok(())
@ -56,7 +56,7 @@ impl<'a> Event<'a> {
// This copies, using the event_store mmap-append api // This copies, using the event_store mmap-append api
pub fn macopy(&self, output: &mut [u8]) -> Result<usize, std::io::Error> { pub fn macopy(&self, output: &mut [u8]) -> Result<usize, std::io::Error> {
if output.len() < self.0.len() { if output.len() < self.0.len() {
return Err(std::io::Error::other(Error::BufferTooSmall)); return Err(std::io::Error::other(ChorusError::BufferTooSmall));
} }
output[..self.0.len()].copy_from_slice(self.0); output[..self.0.len()].copy_from_slice(self.0);
Ok(self.0.len()) Ok(self.0.len())
@ -144,7 +144,7 @@ impl<'a> Event<'a> {
let hashref = <sha256::Hash as AsRef<[u8]>>::as_ref(&hash); let hashref = <sha256::Hash as AsRef<[u8]>>::as_ref(&hash);
if hashref != self.id().as_slice() { if hashref != self.id().as_slice() {
return Err(Error::BadEventId); return Err(ChorusError::BadEventId.into());
} }
let pubkey = XOnlyPublicKey::from_slice(self.pubkey().as_slice())?; let pubkey = XOnlyPublicKey::from_slice(self.pubkey().as_slice())?;

View File

@ -1,12 +1,12 @@
use crate::error::{ChorusError, Error};
use crate::types::parse::json_escape::json_unescape; use crate::types::parse::json_escape::json_unescape;
use crate::types::parse::json_parse::*; use crate::types::parse::json_parse::*;
use crate::Error;
/// Parses a JSON filter from the `input` buffer. Places the parsed filter into the `output` buffer. /// Parses a JSON filter from the `input` buffer. Places the parsed filter into the `output` buffer.
/// Returns the count of consumed bytes and output bytes /// Returns the count of consumed bytes and output bytes
pub fn parse_json_filter(input: &[u8], output: &mut [u8]) -> Result<(usize, usize), Error> { pub fn parse_json_filter(input: &[u8], output: &mut [u8]) -> Result<(usize, usize), Error> {
if input.len() < 2 { if input.len() < 2 {
return Err(Error::JsonBadFilter("Too short", 0)); return Err(ChorusError::JsonBadFilter("Too short", 0).into());
} }
// This tracks where we are currently looking in the input as we scan forward. // This tracks where we are currently looking in the input as we scan forward.
@ -76,7 +76,7 @@ pub fn parse_json_filter(input: &[u8], output: &mut [u8]) -> Result<(usize, usiz
if inpos + 4 <= input.len() && &input[inpos..inpos + 4] == b"ids\"" { if inpos + 4 <= input.len() && &input[inpos..inpos + 4] == b"ids\"" {
// Check for duplicate // Check for duplicate
if found & HAVE_IDS == HAVE_IDS { if found & HAVE_IDS == HAVE_IDS {
return Err(Error::JsonBadFilter("Duplicate id field", inpos)); return Err(ChorusError::JsonBadFilter("Duplicate id field", inpos).into());
} }
inpos += 4; inpos += 4;
@ -97,7 +97,7 @@ pub fn parse_json_filter(input: &[u8], output: &mut [u8]) -> Result<(usize, usiz
} else if inpos + 8 <= input.len() && &input[inpos..inpos + 8] == b"authors\"" { } else if inpos + 8 <= input.len() && &input[inpos..inpos + 8] == b"authors\"" {
// Check for duplicate // Check for duplicate
if found & HAVE_AUTHORS == HAVE_AUTHORS { if found & HAVE_AUTHORS == HAVE_AUTHORS {
return Err(Error::JsonBadFilter("Duplicate authors field", inpos)); return Err(ChorusError::JsonBadFilter("Duplicate authors field", inpos).into());
} }
inpos += 8; inpos += 8;
@ -117,7 +117,7 @@ pub fn parse_json_filter(input: &[u8], output: &mut [u8]) -> Result<(usize, usiz
} else if inpos + 6 <= input.len() && &input[inpos..inpos + 6] == b"kinds\"" { } else if inpos + 6 <= input.len() && &input[inpos..inpos + 6] == b"kinds\"" {
// Check for duplicate // Check for duplicate
if found & HAVE_KINDS == HAVE_KINDS { if found & HAVE_KINDS == HAVE_KINDS {
return Err(Error::JsonBadFilter("Duplicate kinds field", inpos)); return Err(ChorusError::JsonBadFilter("Duplicate kinds field", inpos).into());
} }
inpos += 6; inpos += 6;
@ -137,7 +137,7 @@ pub fn parse_json_filter(input: &[u8], output: &mut [u8]) -> Result<(usize, usiz
} else if inpos + 6 <= input.len() && &input[inpos..inpos + 6] == b"since\"" { } else if inpos + 6 <= input.len() && &input[inpos..inpos + 6] == b"since\"" {
// Check for duplicate // Check for duplicate
if found & HAVE_SINCE == HAVE_SINCE { if found & HAVE_SINCE == HAVE_SINCE {
return Err(Error::JsonBadFilter("Duplicate since field", inpos)); return Err(ChorusError::JsonBadFilter("Duplicate since field", inpos).into());
} }
inpos += 6; inpos += 6;
@ -149,7 +149,7 @@ pub fn parse_json_filter(input: &[u8], output: &mut [u8]) -> Result<(usize, usiz
} else if inpos + 6 <= input.len() && &input[inpos..inpos + 6] == b"until\"" { } else if inpos + 6 <= input.len() && &input[inpos..inpos + 6] == b"until\"" {
// Check for duplicate // Check for duplicate
if found & HAVE_UNTIL == HAVE_UNTIL { if found & HAVE_UNTIL == HAVE_UNTIL {
return Err(Error::JsonBadFilter("Duplicate until field", inpos)); return Err(ChorusError::JsonBadFilter("Duplicate until field", inpos).into());
} }
inpos += 6; inpos += 6;
@ -161,7 +161,7 @@ pub fn parse_json_filter(input: &[u8], output: &mut [u8]) -> Result<(usize, usiz
} else if inpos + 6 <= input.len() && &input[inpos..inpos + 6] == b"limit\"" { } else if inpos + 6 <= input.len() && &input[inpos..inpos + 6] == b"limit\"" {
// Check for duplicate // Check for duplicate
if found & HAVE_LIMIT == HAVE_LIMIT { if found & HAVE_LIMIT == HAVE_LIMIT {
return Err(Error::JsonBadFilter("Duplicate limit field", inpos)); return Err(ChorusError::JsonBadFilter("Duplicate limit field", inpos).into());
} }
inpos += 6; inpos += 6;
@ -189,7 +189,7 @@ pub fn parse_json_filter(input: &[u8], output: &mut [u8]) -> Result<(usize, usiz
// Remember we found this tag in the `found_tags` bitfield // Remember we found this tag in the `found_tags` bitfield
if let Some(bit) = letter_to_tag_bit(letter) { if let Some(bit) = letter_to_tag_bit(letter) {
if found_tags & bit == bit { if found_tags & bit == bit {
return Err(Error::JsonBadFilter("Duplicate tag", inpos)); return Err(ChorusError::JsonBadFilter("Duplicate tag", inpos).into());
} }
found_tags |= bit; found_tags |= bit;
} }
@ -250,10 +250,9 @@ pub fn parse_json_filter(input: &[u8], output: &mut [u8]) -> Result<(usize, usiz
} }
let u = read_u64(input, &mut inpos)?; let u = read_u64(input, &mut inpos)?;
if u > 65535 { if u > 65535 {
return Err(Error::JsonBadFilter( return Err(
"Filter has kind number too large", ChorusError::JsonBadFilter("Filter has kind number too large", inpos).into(),
inpos, );
));
} }
output[end..end + 2].copy_from_slice((u as u16).to_ne_bytes().as_slice()); output[end..end + 2].copy_from_slice((u as u16).to_ne_bytes().as_slice());
num_kinds += 1; num_kinds += 1;
@ -321,7 +320,7 @@ pub fn parse_json_filter(input: &[u8], output: &mut [u8]) -> Result<(usize, usiz
} }
if end > 65535 { if end > 65535 {
return Err(Error::JsonBadFilter("Filter is too long", end)); return Err(ChorusError::JsonBadFilter("Filter is too long", end).into());
} }
// Write length of filter // Write length of filter

View File

@ -1,5 +1,5 @@
use super::{Event, Id, Kind, Pubkey, Tags, Time}; use super::{Event, Id, Kind, Pubkey, Tags, Time};
use crate::Error; use crate::error::{ChorusError, Error};
use std::fmt; use std::fmt;
mod json_filter; mod json_filter;
@ -47,18 +47,18 @@ impl<'a> Filter<'a> {
pub fn delineate(input: &'a [u8]) -> Result<Filter<'a>, Error> { pub fn delineate(input: &'a [u8]) -> Result<Filter<'a>, Error> {
if input.len() < ARRAYS_OFFSET { if input.len() < ARRAYS_OFFSET {
return Err(Error::EndOfInput); return Err(ChorusError::EndOfInput.into());
} }
let len = parse_u16!(input, 0) as usize; let len = parse_u16!(input, 0) as usize;
if input.len() < len { if input.len() < len {
return Err(Error::EndOfInput); return Err(ChorusError::EndOfInput.into());
} }
Ok(Filter(&input[0..len])) Ok(Filter(&input[0..len]))
} }
pub fn copy(&self, output: &mut [u8]) -> Result<(), Error> { pub fn copy(&self, output: &mut [u8]) -> Result<(), Error> {
if output.len() < self.0.len() { if output.len() < self.0.len() {
return Err(Error::EndOfInput); return Err(ChorusError::EndOfInput.into());
} }
output[..self.0.len()].copy_from_slice(self.0); output[..self.0.len()].copy_from_slice(self.0);
Ok(()) Ok(())

View File

@ -1,4 +1,4 @@
use crate::Error; use crate::error::Error;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::fmt; use std::fmt;

View File

@ -1,5 +1,5 @@
use super::utf8::{encode_utf8, next_code_point}; use super::utf8::{encode_utf8, next_code_point};
use crate::Error; use crate::error::{ChorusError, Error};
// LITERAL UNESCAPED: 0x20-0x21, 0x23-0x5B, 0x5D-10FFFF // LITERAL UNESCAPED: 0x20-0x21, 0x23-0x5B, 0x5D-10FFFF
// ESCAPES: \" \\ \/ /b /f /n /r /t // ESCAPES: \" \\ \/ /b /f /n /r /t
@ -13,7 +13,7 @@ pub fn json_escape(input: &[u8], out: &mut [u8]) -> Result<usize, Error> {
// closure to output bytes // closure to output bytes
let mut output = |s: &[u8]| -> Result<(), Error> { let mut output = |s: &[u8]| -> Result<(), Error> {
if out.len() < write_pos + s.len() { if out.len() < write_pos + s.len() {
Err(Error::BufferTooSmall) Err(ChorusError::BufferTooSmall.into())
} else { } else {
out[write_pos..write_pos + s.len()].copy_from_slice(s); out[write_pos..write_pos + s.len()].copy_from_slice(s);
write_pos += s.len(); write_pos += s.len();
@ -51,7 +51,9 @@ pub fn json_escape(input: &[u8], out: &mut [u8]) -> Result<usize, Error> {
macro_rules! output_slice { macro_rules! output_slice {
($slice:expr, $out:expr, $pos:expr) => { ($slice:expr, $out:expr, $pos:expr) => {
if $out.len() < *$pos + $slice.len() { if $out.len() < *$pos + $slice.len() {
Err(Error::BufferTooSmall) Err(Into::<crate::error::Error>::into(
crate::error::ChorusError::BufferTooSmall,
))
} else { } else {
$out[*$pos..*$pos + $slice.len()].copy_from_slice($slice); $out[*$pos..*$pos + $slice.len()].copy_from_slice($slice);
*$pos += $slice.len(); *$pos += $slice.len();
@ -63,7 +65,9 @@ macro_rules! output_slice {
macro_rules! output_byte { macro_rules! output_byte {
($byte:expr, $out:expr, $pos:expr) => { ($byte:expr, $out:expr, $pos:expr) => {
if $out.len() < *$pos + 1 { if $out.len() < *$pos + 1 {
Err(Error::BufferTooSmall) Err(Into::<crate::error::Error>::into(
crate::error::ChorusError::BufferTooSmall,
))
} else { } else {
unsafe { *$out.get_unchecked_mut(*$pos) = $byte }; unsafe { *$out.get_unchecked_mut(*$pos) = $byte };
*$pos += 1; *$pos += 1;
@ -99,7 +103,7 @@ pub fn json_unescape(input: &[u8], out: &mut [u8]) -> Result<(usize, usize), Err
if inescape { if inescape {
inescape = false; inescape = false;
if codepoint > 255 { if codepoint > 255 {
return Err(Error::JsonEscape); return Err(ChorusError::JsonEscape.into());
} }
match codepoint as u8 { match codepoint as u8 {
QUOTE | BACKSLASH | SLASH => { QUOTE | BACKSLASH | SLASH => {
@ -111,17 +115,17 @@ pub fn json_unescape(input: &[u8], out: &mut [u8]) -> Result<(usize, usize), Err
b'r' => output_byte!(CR, out, &mut write_pos)?, b'r' => output_byte!(CR, out, &mut write_pos)?,
b't' => output_byte!(TAB, out, &mut write_pos)?, b't' => output_byte!(TAB, out, &mut write_pos)?,
b'u' => uescape = Some((0, 0)), b'u' => uescape = Some((0, 0)),
_ => return Err(Error::JsonEscape), // nothing else is a legal escape _ => return Err(ChorusError::JsonEscape.into()), // nothing else is a legal escape
} }
} else if let Some((digit, total)) = uescape { } else if let Some((digit, total)) = uescape {
// must be a digit // must be a digit
if !(48..=57).contains(&codepoint) { if !(48..=57).contains(&codepoint) {
return Err(Error::JsonEscape); return Err(ChorusError::JsonEscape.into());
} }
let total = total + ((codepoint - 48) << (4 * (3 - digit))); let total = total + ((codepoint - 48) << (4 * (3 - digit)));
if digit >= 3 { if digit >= 3 {
if (0xD800..=0xDFFF).contains(&total) { if (0xD800..=0xDFFF).contains(&total) {
return Err(Error::JsonEscapeSurrogate); return Err(ChorusError::JsonEscapeSurrogate.into());
} }
let s = encode_utf8(total, &mut out[write_pos..])?; let s = encode_utf8(total, &mut out[write_pos..])?;
write_pos += s; write_pos += s;
@ -138,7 +142,7 @@ pub fn json_unescape(input: &[u8], out: &mut [u8]) -> Result<(usize, usize), Err
// ending double quote // ending double quote
break; break;
} else { } else {
return Err(Error::JsonBadStringChar(codepoint)); return Err(ChorusError::JsonBadStringChar(codepoint).into());
} }
p += size; p += size;
} }

View File

@ -1,5 +1,5 @@
use super::json_escape::json_unescape; use super::json_escape::json_unescape;
use crate::Error; use crate::error::{ChorusError, Error};
#[inline] #[inline]
pub fn eat_whitespace(input: &[u8], inposp: &mut usize) { pub fn eat_whitespace(input: &[u8], inposp: &mut usize) {
@ -18,16 +18,12 @@ pub fn eat_whitespace_and_commas(input: &[u8], inposp: &mut usize) {
#[inline] #[inline]
pub fn verify_char(input: &[u8], ch: u8, inposp: &mut usize) -> Result<(), Error> { pub fn verify_char(input: &[u8], ch: u8, inposp: &mut usize) -> Result<(), Error> {
if *inposp >= input.len() { if *inposp >= input.len() {
Err(Error::JsonBad("Too Short or Missing Fields", *inposp)) Err(ChorusError::JsonBad("Too Short or Missing Fields", *inposp).into())
} else if input[*inposp] == ch { } else if input[*inposp] == ch {
*inposp += 1; *inposp += 1;
Ok(()) Ok(())
} else { } else {
Err(Error::JsonBadCharacter( Err(ChorusError::JsonBadCharacter(input[*inposp] as char, *inposp, ch as char).into())
input[*inposp] as char,
*inposp,
ch as char,
))
} }
} }
@ -42,7 +38,7 @@ pub fn next_object_field(input: &[u8], inposp: &mut usize) -> Result<bool, Error
eat_whitespace(input, inposp); eat_whitespace(input, inposp);
// next comes either comma or end brace // next comes either comma or end brace
if *inposp >= input.len() { if *inposp >= input.len() {
return Err(Error::JsonBad("Too short", *inposp)); return Err(ChorusError::JsonBad("Too short", *inposp).into());
} }
if input[*inposp] == b'}' { if input[*inposp] == b'}' {
*inposp += 1; *inposp += 1;
@ -51,14 +47,14 @@ pub fn next_object_field(input: &[u8], inposp: &mut usize) -> Result<bool, Error
*inposp += 1; *inposp += 1;
Ok(false) Ok(false)
} else { } else {
Err(Error::JsonBad("Unexpected char", *inposp)) Err(ChorusError::JsonBad("Unexpected char", *inposp).into())
} }
} }
pub fn read_id(input: &[u8], inposp: &mut usize, output: &mut [u8]) -> Result<(), Error> { pub fn read_id(input: &[u8], inposp: &mut usize, output: &mut [u8]) -> Result<(), Error> {
verify_char(input, b'"', inposp)?; verify_char(input, b'"', inposp)?;
if *inposp + 64 >= input.len() { if *inposp + 64 >= input.len() {
return Err(Error::JsonBad("Too short reading id", *inposp)); return Err(ChorusError::JsonBad("Too short reading id", *inposp).into());
} }
// Read the hex ID and write the binary ID into the output event structure // Read the hex ID and write the binary ID into the output event structure
read_hex!(&input[*inposp..*inposp + 64], &mut output[..32], 32)?; read_hex!(&input[*inposp..*inposp + 64], &mut output[..32], 32)?;
@ -70,7 +66,7 @@ pub fn read_id(input: &[u8], inposp: &mut usize, output: &mut [u8]) -> Result<()
pub fn read_pubkey(input: &[u8], inposp: &mut usize, output: &mut [u8]) -> Result<(), Error> { pub fn read_pubkey(input: &[u8], inposp: &mut usize, output: &mut [u8]) -> Result<(), Error> {
verify_char(input, b'"', inposp)?; verify_char(input, b'"', inposp)?;
if *inposp + 64 >= input.len() { if *inposp + 64 >= input.len() {
return Err(Error::JsonBad("Too short reading pubkey", *inposp)); return Err(ChorusError::JsonBad("Too short reading pubkey", *inposp).into());
} }
// Read the hex pubkey and write the binary pubkey into the output event structure // Read the hex pubkey and write the binary pubkey into the output event structure
read_hex!(&input[*inposp..*inposp + 64], &mut output[..32], 32)?; read_hex!(&input[*inposp..*inposp + 64], &mut output[..32], 32)?;
@ -88,10 +84,11 @@ pub fn read_u64(input: &[u8], inposp: &mut usize) -> Result<u64, Error> {
*inposp += 1; *inposp += 1;
} }
if !any { if !any {
return Err(Error::JsonBad( return Err(ChorusError::JsonBad(
"Created at must be a positive or zero valued number", "Created at must be a positive or zero valued number",
*inposp, *inposp,
)); )
.into());
} }
Ok(value) Ok(value)
} }
@ -105,13 +102,14 @@ pub fn read_kind(input: &[u8], inposp: &mut usize) -> Result<u16, Error> {
*inposp += 1; *inposp += 1;
} }
if !any { if !any {
return Err(Error::JsonBad( return Err(ChorusError::JsonBad(
"Kind at must be a positive or zero valued number", "Kind at must be a positive or zero valued number",
*inposp, *inposp,
)); )
.into());
} }
if value > 65535 { if value > 65535 {
Err(Error::JsonBad("Kind larger than 65535", *inposp)) Err(ChorusError::JsonBad("Kind larger than 65535", *inposp).into())
} else { } else {
Ok(value as u16) Ok(value as u16)
} }
@ -173,7 +171,7 @@ pub fn read_tags_array(
} }
eat_whitespace(input, inposp); eat_whitespace(input, inposp);
} }
_ => return Err(Error::JsonBad("Tag array bad character", *inposp)), _ => return Err(ChorusError::JsonBad("Tag array bad character", *inposp).into()),
} }
} }
@ -191,7 +189,7 @@ pub fn count_tags(input: &[u8], mut inpos: usize) -> Result<usize, Error> {
match input[inpos] { match input[inpos] {
b']' => return Ok(0), // no tags b']' => return Ok(0), // no tags
b'[' => (), // expected b'[' => (), // expected
_ => return Err(Error::JsonBad("Tag array bad initial character", inpos)), _ => return Err(ChorusError::JsonBad("Tag array bad initial character", inpos).into()),
} }
let mut count = 1; let mut count = 1;
@ -210,7 +208,7 @@ pub fn count_tags(input: &[u8], mut inpos: usize) -> Result<usize, Error> {
burn_tag(input, &mut inpos)?; burn_tag(input, &mut inpos)?;
eat_whitespace(input, &mut inpos); eat_whitespace(input, &mut inpos);
} }
_ => return Err(Error::JsonBad("Tag array bad character", inpos)), _ => return Err(ChorusError::JsonBad("Tag array bad character", inpos).into()),
} }
} }
} }
@ -249,7 +247,7 @@ pub fn read_tag(
*inposp += 1; *inposp += 1;
break; break;
} }
_ => return Err(Error::JsonBad("Tag array bad character", *inposp)), _ => return Err(ChorusError::JsonBad("Tag array bad character", *inposp).into()),
} }
} }
@ -284,7 +282,7 @@ pub fn read_content(
pub fn read_sig(input: &[u8], inposp: &mut usize, output: &mut [u8]) -> Result<(), Error> { pub fn read_sig(input: &[u8], inposp: &mut usize, output: &mut [u8]) -> Result<(), Error> {
verify_char(input, b'"', inposp)?; verify_char(input, b'"', inposp)?;
if *inposp + 128 >= input.len() { if *inposp + 128 >= input.len() {
return Err(Error::JsonBad("Too short reading sig", *inposp)); return Err(ChorusError::JsonBad("Too short reading sig", *inposp).into());
} }
// Read the hex sig and write the binary sig into the output event structure // Read the hex sig and write the binary sig into the output event structure
read_hex!(&input[*inposp..*inposp + 128], &mut output[80..144], 64)?; read_hex!(&input[*inposp..*inposp + 128], &mut output[80..144], 64)?;
@ -307,7 +305,7 @@ pub fn burn_string(input: &[u8], inposp: &mut usize) -> Result<(), Error> {
*inposp += 1; *inposp += 1;
Ok(()) Ok(())
} else { } else {
Err(Error::JsonBad("Unterminated string", *inposp)) Err(ChorusError::JsonBad("Unterminated string", *inposp).into())
} }
} }
@ -372,10 +370,7 @@ pub fn burn_array(input: &[u8], inposp: &mut usize) -> Result<(), Error> {
pub fn burn_value(input: &[u8], inposp: &mut usize) -> Result<(), Error> { pub fn burn_value(input: &[u8], inposp: &mut usize) -> Result<(), Error> {
if *inposp >= input.len() { if *inposp >= input.len() {
return Err(Error::JsonBad( return Err(ChorusError::JsonBad("Too short burning an unused JSON value", *inposp).into());
"Too short burning an unused JSON value",
*inposp,
));
} }
match input[*inposp] { match input[*inposp] {
b'"' => { b'"' => {
@ -398,10 +393,11 @@ pub fn burn_value(input: &[u8], inposp: &mut usize) -> Result<(), Error> {
if b"123456789".contains(&input[*inposp]) { if b"123456789".contains(&input[*inposp]) {
burn_number(input, inposp)? burn_number(input, inposp)?
} else { } else {
return Err(Error::JsonBad( return Err(ChorusError::JsonBad(
"Too short burning an unused JSON value", "Too short burning an unused JSON value",
*inposp, *inposp,
)); )
.into());
} }
} }
} }
@ -414,7 +410,7 @@ pub fn burn_null(input: &[u8], inposp: &mut usize) -> Result<(), Error> {
*inposp += 4; *inposp += 4;
Ok(()) Ok(())
} else { } else {
Err(Error::JsonBad("Expected null", *inposp)) Err(ChorusError::JsonBad("Expected null", *inposp).into())
} }
} }
@ -423,7 +419,7 @@ pub fn burn_true(input: &[u8], inposp: &mut usize) -> Result<(), Error> {
*inposp += 4; *inposp += 4;
Ok(()) Ok(())
} else { } else {
Err(Error::JsonBad("Expected true", *inposp)) Err(ChorusError::JsonBad("Expected true", *inposp).into())
} }
} }
@ -432,7 +428,7 @@ pub fn burn_false(input: &[u8], inposp: &mut usize) -> Result<(), Error> {
*inposp += 5; *inposp += 5;
Ok(()) Ok(())
} else { } else {
Err(Error::JsonBad("Expected false", *inposp)) Err(ChorusError::JsonBad("Expected false", *inposp).into())
} }
} }

View File

@ -1,4 +1,4 @@
use crate::Error; use crate::error::{ChorusError, Error};
// Reads the next code point if UTF-8, and returns it along with the number of characters // Reads the next code point if UTF-8, and returns it along with the number of characters
// that make it up. // that make it up.
@ -18,7 +18,7 @@ pub fn next_code_point(input: &[u8]) -> Result<Option<(u32, usize)>, Error> {
// Decode from a byte combination out of: [[[x y] z] w] // Decode from a byte combination out of: [[[x y] z] w]
let init = utf8_first_byte(x, 2); let init = utf8_first_byte(x, 2);
if len < 2 { if len < 2 {
return Err(Error::Utf8Error); return Err(ChorusError::Utf8Error.into());
} }
let y = input[1]; let y = input[1];
let mut ch = utf8_acc_cont_byte(init, y); let mut ch = utf8_acc_cont_byte(init, y);
@ -26,7 +26,7 @@ pub fn next_code_point(input: &[u8]) -> Result<Option<(u32, usize)>, Error> {
// [[x y z] w] case // [[x y z] w] case
// 5th bit in 0xE0 .. 0xEF is always clear, so `init` is still valid // 5th bit in 0xE0 .. 0xEF is always clear, so `init` is still valid
if len < 3 { if len < 3 {
return Err(Error::Utf8Error); return Err(ChorusError::Utf8Error.into());
} }
let z = input[2]; let z = input[2];
let y_z = utf8_acc_cont_byte((y & CONT_MASK) as u32, z); let y_z = utf8_acc_cont_byte((y & CONT_MASK) as u32, z);
@ -35,7 +35,7 @@ pub fn next_code_point(input: &[u8]) -> Result<Option<(u32, usize)>, Error> {
// [x y z w] case // [x y z w] case
// use only the lower 3 bits of `init` // use only the lower 3 bits of `init`
if len < 4 { if len < 4 {
return Err(Error::Utf8Error); return Err(ChorusError::Utf8Error.into());
} }
let w = input[3]; let w = input[3];
ch = (init & 7) << 18 | utf8_acc_cont_byte(y_z, w); ch = (init & 7) << 18 | utf8_acc_cont_byte(y_z, w);
@ -78,7 +78,7 @@ pub fn encode_utf8(code: u32, dst: &mut [u8]) -> Result<usize, Error> {
*dst.get_unchecked_mut(3) = (code & 0x3F) as u8 | TAG_CONT; *dst.get_unchecked_mut(3) = (code & 0x3F) as u8 | TAG_CONT;
4 4
} else { } else {
return Err(Error::BufferTooSmall); return Err(ChorusError::BufferTooSmall.into());
} }
}; };
Ok(len) Ok(len)

View File

@ -1,4 +1,4 @@
use crate::Error; use crate::error::{ChorusError, Error};
use std::fmt; use std::fmt;
/* /*
@ -23,11 +23,11 @@ impl<'a> Tags<'a> {
// this marks off the slice of bytes that represent the tags from a potentially longer input // this marks off the slice of bytes that represent the tags from a potentially longer input
pub fn delineate(input: &'a [u8]) -> Result<Tags<'a>, Error> { pub fn delineate(input: &'a [u8]) -> Result<Tags<'a>, Error> {
if input.len() < 2 { if input.len() < 2 {
return Err(Error::EndOfInput); return Err(ChorusError::EndOfInput.into());
} }
let len = parse_u16!(input, 0) as usize; let len = parse_u16!(input, 0) as usize;
if input.len() < len { if input.len() < len {
return Err(Error::EndOfInput); return Err(ChorusError::EndOfInput.into());
} }
Ok(Tags(&input[0..len])) Ok(Tags(&input[0..len]))
} }
@ -35,7 +35,7 @@ impl<'a> Tags<'a> {
// This copies // This copies
pub fn copy(&self, output: &mut [u8]) -> Result<(), Error> { pub fn copy(&self, output: &mut [u8]) -> Result<(), Error> {
if output.len() < self.0.len() { if output.len() < self.0.len() {
return Err(Error::BufferTooSmall); return Err(ChorusError::BufferTooSmall.into());
} }
output[..self.0.len()].copy_from_slice(self.0); output[..self.0.len()].copy_from_slice(self.0);
Ok(()) Ok(())