#serde #async #data #deserialize #format #api #future

async_serde

Use Serde as a general-purpose data format API

1 unstable release

0.1.0 Sep 26, 2022

#2907 in Parser implementations

0BSD license

31KB
727 lines

Async Serde

This is a crate for async fn serde. It's not necessarily more efficient, merely different. It allows using serde to interact with data formats (like JSON, etc) directly instead of going through deserialization.

Its main feature is the ability to trivially apply non-deterministic (in the automaton sense) transformations directly onto the deserialization process. This is particularly useful if you happen to be making a jq clone that operates directly on the data stream instead of loading the whole data stream into an in-memory data structure first.

Note

Note that the types Instructor and Step can be passed around freely in a Run impl. While not unsound, this can lead to hard-to-debug errors. It's recommended to only use these as indicated in these examples, to avoid the hard-to-debug runtime errors.

Examples

use std::borrow::Cow;

use async_serde::Deserialize;
use async_serde::Inspect;
use async_serde::Instructor;
use async_serde::Run;
use async_serde::Visit;
use async_trait::async_trait;

struct Foo;
#[async_trait(?Send)]
impl<'de, E: serde::de::Error> Run<'de, E> for Foo {
    type Output = Cow<'de, str>;
    async fn run(
        self,
        instructor: Instructor<'_, 'de>
    ) -> Result<Self::Output, E> {
        let step = instructor.ask(Deserialize::String).unwrap().await;
        match step.kind() {
            Visit::Str => {
                step.inspect_string(|s| {
                    match s {
                        Inspect::Borrowed(s) => Cow::from(s),
                        Inspect::Owned(s) => Cow::from(String::from(s)),
                        Inspect::Buffered(s) => Cow::from(s.to_owned()),
                    }
                }).ok_or_else(|| E::custom("wrong type"))
            },
            _ => Err(E::custom("wrong type")),
        }
    }
}

fn main() {
    let mut json = serde_json::Deserializer::from_str("\"hello\"");
    let exec = async_serde::Executor::new(&mut json);
    // this is returning an Result<Option<Cow<'de, str>>, Error>
    let res = exec.run::<_, serde_json::Error>(Foo);
    assert_eq!(res.unwrap(), "hello");
}
use std::borrow::Cow;

use async_serde::Deserialize;
use async_serde::Inspect;
use async_serde::Instructor;
use async_serde::Run;
use async_serde::Visit;
use async_trait::async_trait;

struct Foo;
#[async_trait(?Send)]
impl<'de, E: serde::de::Error> Run<'de, E> for Foo {
    type Output = [Vec<Cow<'de, str>>; 2];
    async fn run(
        self,
        instructor: Instructor<'_, 'de>
    ) -> Result<Self::Output, E> {
        let mut step = instructor.ask(Deserialize::Seq).unwrap().await;
        match step.kind() {
            Visit::Seq => {
                let step2 = step.cloned();
                match futures::join!(
                    step.inspect_seq(|s| async move {
                        // TODO
                        Ok(Vec::new())
                    }).ok_or_else(|| E::custom("wrong type"))?,
                    step2.inspect_seq(|s| async move {
                        // TODO
                        Ok(Vec::new())
                    }).ok_or_else(|| E::custom("wrong type"))?
                ) {
                    (a, b) => Ok([a?, b?])
                }
            },
            _ => Err(E::custom("wrong type")),
        }
    }
}

fn main() {
    let mut json = serde_json::Deserializer::from_str("[\"a\", \"b\"]");
    let exec = async_serde::Executor::new(&mut json);
    // this is returning an Result<Option<Cow<'de, str>>, Error>
    let res = exec.run::<_, serde_json::Error>(Foo).unwrap();
    assert_eq!(res[0], &[Cow::from("a"), "b".into()][..]);
    assert_eq!(res[1], &[Cow::from("a"), "b".into()][..]);
}

Dependencies

~1–1.8MB
~39K SLoC