Skip to content

Unable to use serde macros in additional_derives when importing wasi::http types #812

Open

Description

@landonxjames

I have a simple library testing out the wasi:http types. When I try to add an additional_derives: [serde::Serialize, serde::Deserialize] to the wit_bindgen::generate! macro definition I get the below error. Not sure if thise repo or the wasi-http repo would be better for this issue, but trying here first.

Reproduction can be found in this repo. Uncommenting this line will cause the error.

error[E0277]: the trait bound `wasi::io::error::Error: Deserialize<'_>` is not satisfied
    --> src/lib.rs:5:1
     |
5    | / wit_bindgen::generate!({
6    | | world: "wasi-http-tests",
7    | | exports: {
8    | |     "wasi-http-tests:component/client/wasi-http-tests-client": WasiHttpTestsClient,
9    | | },
10   | | additional_derives: [serde::Serialize, serde::Deserialize]
11   | | });
     | |__^ the trait `Deserialize<'_>` is not implemented for `wasi::io::error::Error`
     |
     = help: the following other types implement trait `Deserialize<'de>`:
               bool
               char
               isize
               i8
               i16
               i32
               i64
               i128
             and 137 others
note: required by a bound in `newtype_variant`
    --> /Users/lnj/.cargo/registry/src/index.crates.io-6f17d22bba15001f/serde-1.0.193/src/de/mod.rs:2119:12
     |
2117 |     fn newtype_variant<T>(self) -> Result<T, Self::Error>
     |        --------------- required by a bound in this associated function
2118 |     where
2119 |         T: Deserialize<'de>,
     |            ^^^^^^^^^^^^^^^^ required by this bound in `VariantAccess::newtype_variant`
     = note: this error originates in the macro `wit_bindgen::generate` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound `wasi::io::error::Error: Serialize` is not satisfied
   --> src/lib.rs:5:1
    |
5   | / wit_bindgen::generate!({
6   | | world: "wasi-http-tests",
7   | | exports: {
8   | |     "wasi-http-tests:component/client/wasi-http-tests-client": WasiHttpTestsClient,
9   | | },
10  | | additional_derives: [serde::Serialize, serde::Deserialize]
11  | | });
    | |__^ the trait `Serialize` is not implemented for `wasi::io::error::Error`
    |
    = help: the following other types implement trait `Serialize`:
              bool
              char
              isize
              i8
              i16
              i32
              i64
              i128
            and 136 others
note: required by a bound in `serialize_newtype_variant`
   --> /Users/lnj/.cargo/registry/src/index.crates.io-6f17d22bba15001f/serde-1.0.193/src/ser/mod.rs:936:12
    |
928 |     fn serialize_newtype_variant<T: ?Sized>(
    |        ------------------------- required by a bound in this associated function
...
936 |         T: Serialize;
    |            ^^^^^^^^^ required by this bound in `Serializer::serialize_newtype_variant`
    = note: this error originates in the macro `wit_bindgen::generate` (in Nightly builds, run with -Z macro-backtrace for more info)

Activity

  1. pchickey commented on Jan 10, 2024

    @pchickey
    Contributor

    wasi::io::error::Error is a resource type, so it will never be able to impl Serialize or Deserialize. So, the bug here is that the derives are being applied to the type alias created for https://github.com/WebAssembly/wasi-http/blob/main/wit/types.wit#L7

  2. added
    gen-rustRelated to bindings for Rust-compiled-to-WebAssembly
    on Feb 14, 2024
  3. landonxjames commented on Mar 27, 2024

    @landonxjames
    Author

    Another related bug I just encountered: When a variant contains a case and the type associated with that case is a resource the serde macros cause a build failure. So the following wit fails to build

    resource perf-event {
        constructor();
        parse-string: func(input: string) -> result<some-event, string>;
      }
    
      resource constructor-perf-event {
        constructor(input: string);
        get-data: func() -> some-event;
      }
    
      variant supported-events {
        none,
        my-event(constructor-perf-event),
        foo(perf-event)
      }
    
      resource variant-perf-event {
        constructor(input: supported-events);
        get-child-event: func() -> supported-events;
      }

    Due to the resource types not implementing Serialize.

    error[E0277]: the trait bound `component::events::PerfEvent: Serialize` is not satisfied
       --> src/bindings.rs:601:46
        |
    601 |                 #[derive(serde::Deserialize, serde::Serialize)]
        |                                              ^^^^^^^^^^^^^^^^ the trait `Serialize` is not implemented for `component::events::PerfEvent`
    ...
    605 |                     Foo(PerfEvent),
        |                         -------------- required by a bound introduced by this call

    I think this is further evidence to motivate some kind of attribute system in WIT so things like serde traits can be properly targeted to the correct types.

  4. LUK3ARK commented on May 26, 2024

    @LUK3ARK

    wasi::io::error::Error is a resource type, so it will never be able to impl Serialize or Deserialize. So, the bug here is that the derives are being applied to the type alias created for https://github.com/WebAssembly/wasi-http/blob/main/wit/types.wit#L7

    This is correct, if I add additional derives, I expect it to only be added to records and not custom resources, or at least a way to specify what resources not to apply to.

    Is there any solution currently to using serde for types but ignoring for resources/ fixing for resources?

  5. thomastaylor312 commented on Aug 29, 2024

    @thomastaylor312
    Contributor

    I am pretty sure this code is mostly unchanged since I wrote it and based on my quick skim again, it does only target records and anything that gets turned into a rust enum. But that is only at the top level. So if a record or variant contains a resource within it, it won't work (because the top level resource doesn't get the attributes). FWIW, I knew we'd run into this sooner rather than later, but we figured it would be good to have so you at least didn't have to do the manual remote derive stuff for something simple (plus this was back far enough I probably didn't know how to solve it well enough at that point).

    The fix here would be to change the generation code

    fn print_typedef_record(&mut self, id: TypeId, record: &Record, docs: &Docs) {
    fn print_rust_enum<'b>(
    to use the Resolve so that you could walk the whole type and check if any nested type is a resource before adding the additional derives.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    gen-rustRelated to bindings for Rust-compiled-to-WebAssembly

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions