forked from Orchid/orchid
Orchid-base uses task-local context.
Everything else is broken at the moment.
This commit is contained in:
@@ -2,13 +2,15 @@ use std::cell::RefCell;
|
||||
use std::ffi::OsStr;
|
||||
use std::fmt;
|
||||
use std::ops::Add;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
|
||||
use futures::future::join_all;
|
||||
use itertools::Itertools;
|
||||
use some_executor::task_local;
|
||||
|
||||
use crate::api;
|
||||
use crate::interner::{Interner, Tok};
|
||||
use crate::interner::{IStr, es, is};
|
||||
use crate::location::Pos;
|
||||
|
||||
/// A point of interest in resolving the error, such as the point where
|
||||
@@ -24,10 +26,10 @@ impl ErrPos {
|
||||
pub fn new(msg: &str, position: Pos) -> Self {
|
||||
Self { message: Some(Arc::new(msg.to_string())), position }
|
||||
}
|
||||
async fn from_api(api: &api::ErrLocation, i: &Interner) -> Self {
|
||||
async fn from_api(api: &api::ErrLocation) -> Self {
|
||||
Self {
|
||||
message: Some(api.message.clone()).filter(|s| !s.is_empty()),
|
||||
position: Pos::from_api(&api.location, i).await,
|
||||
position: Pos::from_api(&api.location).await,
|
||||
}
|
||||
}
|
||||
fn to_api(&self) -> api::ErrLocation {
|
||||
@@ -51,7 +53,7 @@ impl fmt::Display for ErrPos {
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct OrcErr {
|
||||
pub description: Tok<String>,
|
||||
pub description: IStr,
|
||||
pub message: Arc<String>,
|
||||
pub positions: Vec<ErrPos>,
|
||||
}
|
||||
@@ -63,16 +65,16 @@ impl OrcErr {
|
||||
locations: self.positions.iter().map(ErrPos::to_api).collect(),
|
||||
}
|
||||
}
|
||||
async fn from_api(api: &api::OrcError, i: &Interner) -> Self {
|
||||
async fn from_api(api: &api::OrcError) -> Self {
|
||||
Self {
|
||||
description: Tok::from_api(api.description, i).await,
|
||||
description: es(api.description).await,
|
||||
message: api.message.clone(),
|
||||
positions: join_all(api.locations.iter().map(|e| ErrPos::from_api(e, i))).await,
|
||||
positions: join_all(api.locations.iter().map(ErrPos::from_api)).await,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl PartialEq<Tok<String>> for OrcErr {
|
||||
fn eq(&self, other: &Tok<String>) -> bool { self.description == *other }
|
||||
impl PartialEq<IStr> for OrcErr {
|
||||
fn eq(&self, other: &IStr) -> bool { self.description == *other }
|
||||
}
|
||||
impl From<OrcErr> for Vec<OrcErr> {
|
||||
fn from(value: OrcErr) -> Self { vec![value] }
|
||||
@@ -122,11 +124,8 @@ impl OrcErrv {
|
||||
self.0.iter().flat_map(|e| e.positions.iter().cloned())
|
||||
}
|
||||
pub fn to_api(&self) -> Vec<api::OrcError> { self.0.iter().map(OrcErr::to_api).collect() }
|
||||
pub async fn from_api<'a>(
|
||||
api: impl IntoIterator<Item = &'a api::OrcError>,
|
||||
i: &Interner,
|
||||
) -> Self {
|
||||
Self(join_all(api.into_iter().map(|e| OrcErr::from_api(e, i))).await)
|
||||
pub async fn from_api<'a>(api: impl IntoIterator<Item = &'a api::OrcError>) -> Self {
|
||||
Self(join_all(api.into_iter().map(OrcErr::from_api)).await)
|
||||
}
|
||||
}
|
||||
impl From<OrcErr> for OrcErrv {
|
||||
@@ -191,12 +190,12 @@ macro_rules! join_ok {
|
||||
(@VALUES) => { Ok(()) };
|
||||
}
|
||||
|
||||
pub fn mk_errv_floating(description: Tok<String>, message: impl AsRef<str>) -> OrcErrv {
|
||||
pub fn mk_errv_floating(description: IStr, message: impl AsRef<str>) -> OrcErrv {
|
||||
mk_errv::<Pos>(description, message, [])
|
||||
}
|
||||
|
||||
pub fn mk_errv<I: Into<ErrPos>>(
|
||||
description: Tok<String>,
|
||||
description: IStr,
|
||||
message: impl AsRef<str>,
|
||||
posv: impl IntoIterator<Item = I>,
|
||||
) -> OrcErrv {
|
||||
@@ -210,45 +209,61 @@ pub fn mk_errv<I: Into<ErrPos>>(
|
||||
|
||||
pub async fn async_io_err<I: Into<ErrPos>>(
|
||||
err: std::io::Error,
|
||||
i: &Interner,
|
||||
posv: impl IntoIterator<Item = I>,
|
||||
) -> OrcErrv {
|
||||
mk_errv(i.i(&err.kind().to_string()).await, err.to_string(), posv)
|
||||
mk_errv(is(&err.kind().to_string()).await, err.to_string(), posv)
|
||||
}
|
||||
|
||||
pub async fn os_str_to_string<'a, I: Into<ErrPos>>(
|
||||
str: &'a OsStr,
|
||||
i: &Interner,
|
||||
pub async fn os_str_to_string<I: Into<ErrPos>>(
|
||||
str: &OsStr,
|
||||
posv: impl IntoIterator<Item = I>,
|
||||
) -> OrcRes<&'a str> {
|
||||
) -> OrcRes<&str> {
|
||||
match str.to_str() {
|
||||
Some(str) => Ok(str),
|
||||
None => Err(mk_errv(
|
||||
i.i("Non-unicode string").await,
|
||||
is("Non-unicode string").await,
|
||||
format!("{str:?} is not representable as unicode"),
|
||||
posv,
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Reporter {
|
||||
errors: RefCell<Vec<OrcErr>>,
|
||||
#[derive(Clone, Default)]
|
||||
struct Reporter {
|
||||
errors: Rc<RefCell<Vec<OrcErr>>>,
|
||||
}
|
||||
|
||||
impl Reporter {
|
||||
pub fn report(&self, e: impl Into<OrcErrv>) { self.errors.borrow_mut().extend(e.into()) }
|
||||
pub fn new() -> Self { Self { errors: RefCell::new(vec![]) } }
|
||||
pub fn errv(self) -> Option<OrcErrv> { OrcErrv::new(self.errors.into_inner()).ok() }
|
||||
pub fn merge<T>(self, res: OrcRes<T>) -> OrcRes<T> {
|
||||
match (res, self.errv()) {
|
||||
(res, None) => res,
|
||||
(Ok(_), Some(errv)) => Err(errv),
|
||||
(Err(e), Some(errv)) => Err(e + errv),
|
||||
}
|
||||
task_local! {
|
||||
static REPORTER: Reporter;
|
||||
}
|
||||
|
||||
pub async fn with_reporter<T>(fut: impl Future<Output = OrcRes<T>>) -> OrcRes<T> {
|
||||
let rep = Reporter::default();
|
||||
let res = REPORTER.scope(rep.clone(), fut).await;
|
||||
let errors = rep.errors.take();
|
||||
match (res, &errors[..]) {
|
||||
(Ok(t), []) => Ok(t),
|
||||
(Ok(_), [_, ..]) => Err(OrcErrv::new(errors).unwrap()),
|
||||
(Err(e), _) => Err(e.extended(errors)),
|
||||
}
|
||||
pub fn is_empty(&self) -> bool { self.errors.borrow().is_empty() }
|
||||
}
|
||||
|
||||
impl Default for Reporter {
|
||||
fn default() -> Self { Self::new() }
|
||||
pub async fn is_erroring() -> bool {
|
||||
REPORTER.with(|r| {
|
||||
!r.expect("Sidechannel errors must be caught by a reporter").errors.borrow().is_empty()
|
||||
})
|
||||
}
|
||||
|
||||
/// Report an error that is fatal and prevents a correct output, but
|
||||
/// still allows the current task to continue and produce an approximate output.
|
||||
/// This can be used for
|
||||
pub fn report(e: impl Into<OrcErrv>) {
|
||||
let errv = e.into();
|
||||
REPORTER.with(|r| match r {
|
||||
Some(r) => r.errors.borrow_mut().extend(errv),
|
||||
None => panic!(
|
||||
"Unhandled error! Sidechannel errors must be caught by an enclosing call to with_reporter.\n\
|
||||
Error: {errv}",
|
||||
),
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user