mod codec;
mod commit;
mod core;
mod js;
mod node;
mod opfs;
mod opfs_io;
mod owner;
mod source;
use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};
pub use core::{BrowserLocalStore, BrowserWorkHandle};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BrowserCommitDurability {
Durable,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BrowserDurabilityGrade {
BrowserFlushed,
}
impl BrowserDurabilityGrade {
#[must_use]
pub const fn label(self) -> &'static str {
match self {
Self::BrowserFlushed => "D-browser-flushed",
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct BrowserBranchVersion {
pub name: String,
pub created: u64,
pub seq: u64,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct BrowserCommitReceipt {
pub grade: BrowserDurabilityGrade,
pub version: BrowserBranchVersion,
pub heads: Vec<(crate::ShardId, crate::tree::Hash)>,
pub advanced: bool,
}
pub struct BrowserRequest<T> {
future: Pin<Box<dyn Future<Output = Result<T, BrowserLocalError>>>>,
}
impl<T> BrowserRequest<T> {
pub(crate) fn new(
future: impl Future<Output = Result<T, BrowserLocalError>> + 'static,
) -> Self {
Self {
future: Box::pin(future),
}
}
}
impl<T> Future for BrowserRequest<T> {
type Output = Result<T, BrowserLocalError>;
fn poll(mut self: Pin<&mut Self>, context: &mut Context<'_>) -> Poll<Self::Output> {
self.future.as_mut().poll(context)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum BrowserSourceError {
JavaScript {
operation: &'static str,
name: String,
message: String,
},
Codec {
message: String,
},
Node {
error: crate::tree::NodeError,
},
NodeHashMismatch {
expected: crate::tree::Hash,
actual: crate::tree::Hash,
},
Tree {
error: crate::tree::TreeError,
},
Branch {
error: crate::branch::BranchError,
},
Backend {
operation: &'static str,
message: String,
},
}
impl BrowserSourceError {
pub(crate) fn codec(message: impl Into<String>) -> Self {
Self::Codec {
message: message.into(),
}
}
pub(crate) fn backend(operation: &'static str, message: impl Into<String>) -> Self {
Self::Backend {
operation,
message: message.into(),
}
}
}
impl std::fmt::Display for BrowserSourceError {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::JavaScript {
operation,
name,
message,
} if name.is_empty() => write!(formatter, "{operation}: {message}"),
Self::JavaScript {
operation,
name,
message,
} => write!(formatter, "{operation}: {name}: {message}"),
Self::Codec { message } => formatter.write_str(message),
Self::Node { error } => error.fmt(formatter),
Self::NodeHashMismatch { expected, actual } => write!(
formatter,
"node hash does not match its bytes: expected {expected}, actual {actual}"
),
Self::Tree { error } => error.fmt(formatter),
Self::Branch { error } => error.fmt(formatter),
Self::Backend { operation, message } => {
write!(formatter, "{operation}: {message}")
}
}
}
}
impl From<String> for BrowserSourceError {
fn from(message: String) -> Self {
Self::codec(message)
}
}
impl From<&str> for BrowserSourceError {
fn from(message: &str) -> Self {
Self::codec(message)
}
}
impl std::error::Error for BrowserSourceError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::Node { error } => Some(error),
Self::Tree { error } => Some(error),
Self::Branch { error } => Some(error),
Self::JavaScript { .. }
| Self::Codec { .. }
| Self::NodeHashMismatch { .. }
| Self::Backend { .. } => None,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum BrowserLocalError {
UnsupportedSubstrate {
probe: &'static str,
browser: String,
evidence: &'static str,
},
UnsupportedStoreFormat {
found: String,
},
StoreGenerationLost {
component: &'static str,
},
NonCanonicalBranchSet {
records: usize,
},
WrongBranchKind {
found: String,
},
NodeFailure {
operation: &'static str,
source: BrowserSourceError,
},
RecordFailure {
operation: &'static str,
source: BrowserSourceError,
},
FenceFailure {
operation: &'static str,
source: BrowserSourceError,
},
WorkerClosed,
}
impl std::fmt::Display for BrowserLocalError {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::UnsupportedSubstrate { probe, browser, .. } => {
write!(
formatter,
"unsupported browser substrate for {probe}: {browser}"
)
}
Self::UnsupportedStoreFormat { found } => {
write!(formatter, "unsupported browser store format: {found}")
}
Self::StoreGenerationLost { component } => {
write!(formatter, "browser store generation lost: {component}")
}
Self::NonCanonicalBranchSet { records } => {
write!(
formatter,
"non-canonical browser branch set: {records} records"
)
}
Self::WrongBranchKind { found } => write!(formatter, "wrong branch kind: {found}"),
Self::NodeFailure { operation, source }
| Self::RecordFailure { operation, source }
| Self::FenceFailure { operation, source } => {
write!(formatter, "browser {operation} failed: {source}")
}
Self::WorkerClosed => formatter.write_str("browser-local owner worker is closed"),
}
}
}
impl std::error::Error for BrowserLocalError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::NodeFailure { source, .. }
| Self::RecordFailure { source, .. }
| Self::FenceFailure { source, .. } => Some(source),
Self::UnsupportedSubstrate { .. }
| Self::UnsupportedStoreFormat { .. }
| Self::StoreGenerationLost { .. }
| Self::NonCanonicalBranchSet { .. }
| Self::WrongBranchKind { .. }
| Self::WorkerClosed => None,
}
}
}