-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
PointerBuf::parse
accepts Into<String>
but does not include the String
in the Err
#96
Comments
PointerBuf::parse
likely takes ownership of the input Into<String>
but does not include it in the Err
PointerBuf::parse
likely takes ownership of input but does not return the String
in the Err
PointerBuf::parse
likely takes ownership of input but does not return the String
in the Err
PointerBuf::parse
likely takes ownership of input but does not return it in the Err
PointerBuf::parse
likely takes ownership of input but does not return it in the Err
PointerBuf::parse
accepts Into<String>
but does not include the String
in the Err
@asmello referencing my comment in our conversation over on the error pull request #93 (comment) |
This is bleed-over from our discussion in #93 but this is what I had in mind for #[derive(Debug, Clone, PartialEq, Eq)]
pub enum Subject {
String {
value: String,
offset: usize,
len: usize,
},
Pointer {
value: PointerBuf,
position: usize,
},
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Report<E> {
pub subject: Subject,
pub error: E,
}
pub trait IntoReport: Sized {
type Value;
fn into_report(self, value: Self::Value) -> Report<Self>;
}
impl IntoReport for crate::ParseError {
type Value = String;
fn into_report(self, value: Self::Value) -> Report<Self> {
let offset = self.complete_offset();
let len = match &self {
Self::NoLeadingBackslash => 1,
Self::InvalidEncoding { offset, .. } => {
if *offset < value.len() - 1 { 2 } else { 1 }
}
};
Report {
subject: Subject::String { value, offset, len },
error: self,
}
}
} The reason I'm mentioning it here is perhaps we could just return Editremove |
Oh no, I don't think it's worth generalising it this much. This is how I envision the ideal API: pub fn parse<'s>(s: impl Into<Cow<'s, str>>) -> Result<Self, ParseError<'s>> {
let s = s.into();
validate(s.as_ref())?;
Ok(Self(s.into_owned()))
}
pub enum ParseError<'s> {
NoLeadingBackslash,
InvalidEncoding(InvalidEncodingError<'s>),
}
#[derive(Error, Diagnostic, Debug)]
#[error("json pointer is malformed due to invalid encoding ('~' not followed by '0' or '1')")]
pub struct InvalidEncodingError<'s> {
#[label]
span: SourceSpan,
#[source_code]
source: Cow<'s, str>
}
impl<'s> InvalidEncodingError<'s> {
pub fn origin(&self) -> Cow<'s, str> { ... } // this is how you recover the original string
pub fn offender(&self) -> &str { ... } // the slice where we found the issue
} My suggestion is to start writing down errors like this explicitly, and then any patterns worth exploiting will be easy to identify. We may actually be better served by a macro. Trying to design some generic types upfront to cover all the different subtypes and nesting cases will be difficult, and I suspect overlap is more restricted than we imagine (consider all the variations of source being string, pointer, owned, borrowed, and nesting enums etc.). |
There's no way around breaks to achieve that API. Here's a rough plan for transitioning a bit more gradually:
2 transitory releases should be plenty for people to migrate, especially since we're in 0.x still. I'll make a point of migrating |
I'm sorry, I've been distracted and haven't been able to devote enough energy to this (or finish my impl).
So there are a few reasons I opted to make the error generic and be an additional layer that a user opts into. I'm going to consolidate reasons here from the other thread we have pertaining to this. First, Second, one of my use cases for Third, there are aspects of having opt-in composition to extend out the verbosity of the error that I really like. In doing so, only users that need the functionality pay for it. On the other hand, I don't really care for this API (and its the best I've come up with since my previous attempt failed): let report = Pointer::parse("invalid~encoding")
.report_err("invalid~encoding")
.unwrap_err();
assert_eq!(report.subject.as_str(), "invalid~encoding");
// alternatively
let err = Pointer::parse("invalid~encoding").unwrap_err();
let report = Report::new("invalid~encoding", err);
assert_eq!(report.subject.as_str(), "invalid~encoding"); Now, having said all that, pretty much every instance where you've voiced concern or dislike of a change I've proposed and implemented, I've regretted not listening. I also do not like that
That's a really solid strategy. I've been really reluctant to pump out so many breaks, especially around errors. I was going to use |
No worries at all, I was in the same situation very recently.
That's reasonable. Not all errors indicate a failure, and the unhappy path is not always uncommon. Makes sense to avoid allocations when that's the case.
Ok, I think I get your intent better now. But I suspect this is better managed by feature flags than a custom trait system. The biggest thing convincing me right now of moving in this direction is that, going from your example, we'd presumably implement
I don't think that works unfortunately, as |
I wasn't sure if there were (or will be) competitors to
Well, sort of, right? We have 3 - 4 errors (
It does, since fn example() -> Result<(), ParseError> {
PointerBuf::parse("")?; // Result<_, ParseBufError>;
Ok(())
} |
Sorry, crossed the wires slightly in my last comment, to clarify the feature flag would be to avoid the cost of compiling with
Yeah, it's a good idea to keep
Ok, interesting, why should we avoid having the pointer attached (even as a reference, I assume) for
Oooh, ok, didn't get that this was the |
We likely take ownership of the input to
PointerBuf::parse
but do not include it in resultingParseError
.PointerBuf::parse
:ParseError
:The text was updated successfully, but these errors were encountered: