Skip to content

Use unsafe (or just pin if theres a safe way) to make API more ergonomic #12

Description

@ZoopOTheGoop

I'm not sure I want to do this, but a solution to #9 #10, is to store a Pin<...> of the payload json in a wrapper struct and deserialize it into a self-referential type with unsafe (giving the stored type a 'static lifetime, but using a method to give it out with a 'a lifetime bound to the &'a self reference).

This is very similar to using a RefCell to cache the result of deserialize. This removes a lot of lifetime handling on the part of the API consumer, as well as makes it much more ergonomic to use the result of a query at your desired call site, since you don't have to bubble up the json payload and parse-on-site. It also allows something like:

struct ResultWrapper<T> {
    json: Pin<String>,
    decoded: T,
}

struct Decoded<'a> {
    // ....
    name: SnapName<'a>,
    // ...
}

impl<'a> From<Decoded<'a>>  for SnapName<'a> {
    fn from(other: Decoded<'_>) -> SnapName<'_> {
        other.name
    }
}

impl<T> ResultWrapper<T> {
    fn to_subfield<F: From<T>>(self) -> ResultWrapper<F> {
        ResultWrapper {
             json: self.json,
             decoded: self.decoded.into(),
        }
    }
}

// ...

let foo = ResultWrapper<FindResult> = get(...);
let name = foo.to_subfield::<SnapName<'_>>();

return name;

This probably doesn't quite work as-is but the concept is sound that since we own the payload Json, we can create conversions into "more filtered" versions.

If we do this, it should definitely be a single type, to minimize unsafe code surface as much as possible.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions