prost icon indicating copy to clipboard operation
prost copied to clipboard

Serializing a Message to Any

Open KaiserKarel opened this issue 4 years ago • 22 comments

I'm unable to find any docs on how to create an Any from a Message. Do I need to serialize the message myself and set the typeURL?

KaiserKarel avatar Apr 05 '20 10:04 KaiserKarel

+1, I need to deserialize an Any to a known type. In other languages, I see there are pack/unpack methods. I couldn't find such methods on the Any type (https://docs.rs/prost-types/0.6.1/src/prost_types/protobuf.rs.html#964-998 )

fridge-dev avatar Apr 12 '20 01:04 fridge-dev

Similar to #277.

fdeantoni avatar May 27 '20 03:05 fdeantoni

Subscribed... I know how to go from a type to Any, but not the other way around.

cetanu avatar Sep 08 '20 12:09 cetanu

The tools for de-serializing an Any type is already there, you can match on the type URL, and decode the value field using Message::decode.

With a little bit of macro magic you don't have to write a lot of code, I have made an example repo. IMO this is simpler and can easily be adapted to your own needs.

petergarnaes avatar Dec 25 '20 21:12 petergarnaes

If there is a mechanism for Message to return type_url, it can support generics.

use prost::Message;
use prost_types::Any;

fn to_any<T>(message: &T) -> Any where T: Message {
    Any {
        type_url: T::type_url().to_string(),
        value: message.encode_to_vec(),
    }
}

fn from_any<T>(message: &Any) -> Result<T, DecodeError> where T: Message + Default {
    if &message.type_url == T::type_url() {
        T::decode(message.value.as_slice())
    } else {
        Err(DecodeError::new("Invalid type_url"))
    }
}

vbkaisetsu avatar Sep 09 '21 10:09 vbkaisetsu

Adding a type_url to Message would definitely help. After that it would be straightforward to add pack/unpack methods for messages.

colin-grapl avatar Nov 10 '21 23:11 colin-grapl

Create a datafusion-proto crate for datafusion protobuf serialization apache/arrow-datafusion#1887

@vbkaisetsu is there a type_url for prost::Message? I don't think there is one if not this will be straightforward

ghost avatar Apr 11 '22 16:04 ghost

@nyanchor I previously created https://github.com/tokio-rs/prost/pull/535 to support seamless seriarization, but it needs further discussion.

vbkaisetsu avatar Apr 11 '22 23:04 vbkaisetsu

Yeah, I think supporting this is a good idea. Will need to dig in a bit more to understand how other languages support this feature.

LucioFranco avatar Apr 12 '22 15:04 LucioFranco

@LucioFranco the simplest way to support it is adding an associated const TYPE_URL: &'static str to either the Message trait (or another specialized trait if adding it to Message is too onerous). Or if there are genuinely good use cases, possibly a static method.

Then prost-build just needs to compute and generate it for each type.

tarcieri avatar Jul 25 '22 21:07 tarcieri

@tarcieri yes, though I don't remember (or couldn't find but didn't look super hard) if there was actually a concrete way to generate that url that isn't google specific etc.

LucioFranco avatar Jul 29 '22 18:07 LucioFranco

To my knowledge the type URLs take the form:

/<package>.<type name>

e.g.

/foo.bar.baz.MyTypeName

tarcieri avatar Jul 29 '22 19:07 tarcieri

Bumping this one up as it's definitely something that will make my life easier.

kurojishi avatar Dec 23 '22 09:12 kurojishi

Do we have any latest process?

Percivalll avatar May 15 '23 07:05 Percivalll

One way to get started would be to add a trait with a carrier for the type URL:

pub trait TypeUrl: Message {
    const TYPE_URL: &'static str;
}

This would avoid the need to immediately populate it for every Message, but provide a common way to implement methods (e.g. on prost_types::Any) for decoding/encoding Message + TypeUrl types from/to Any.

At least initially, the TypeUrl annotations could be added manually, until such a time that prost-build can emit them automatically.

Edit: opened a PR with this idea: #858

tarcieri avatar May 15 '23 22:05 tarcieri

I opened #896 as my latest attempt to implement this feature

tarcieri avatar Aug 14 '23 16:08 tarcieri

@tarcieri would you mind indicating why Name + Pkg needed in your implementation ? also, would you mind indicating why type_url() isn't exported by default on Prost::Message ?

I can implement prost-build; however, a better approach would remove those unnecessary traits

fn macros(fds: FileDescriptorSet) {
  for fd in &fds.file {
   .....
    for buf in &fd.message_type {
      ....
      let tokens = quote! {
          impl prost::Name for #bufname {
              const NAME: &'static str = #bufurl;
              const PACKAGE: &'static str = #pkg;
              fn type_url() -> String {
                  #bufurl.to_string()
              }
          }
      };
    }
  }
}

journaux avatar Sep 22 '23 17:09 journaux

would you mind indicating why Name + Pkg needed in your implementation

Please see the discussion here: https://github.com/tokio-rs/prost/pull/858#discussion_r1262305092

also, would you mind indicating why type_url() isn't exported by default on Prost::Message

There is currently no prost-build support, so trying to do that would break all code generation in addition to all currently generated code, as it would be a breaking change to Message.

In the future when there is prost-build support, it might make sense to combine Name into Message.

tarcieri avatar Sep 22 '23 18:09 tarcieri

so it’s a problem with the design + impl not any technical decision / desire ?

If that’s the case — prost::Message::type_url can trivially be added to prost-build

journaux avatar Sep 24 '23 23:09 journaux

It’s something that could potentially be merged into Message in the next breaking release provided prost-build support were implemented, yes

tarcieri avatar Sep 24 '23 23:09 tarcieri

Merging Name into Message might be problematic for custom Message implementations like prost_reflect::DynamicMessage, unless the string types were changed to something like Cow<'static, str> to allow an owned string.

andrewhickman avatar Nov 03 '23 02:11 andrewhickman

Yeah, the Name trait in its current form is poorly suited to anything dynamic. We could potentially refactor it to make it easier to use for that use case (and potentially trait object safe) in the next release

tarcieri avatar Nov 03 '23 15:11 tarcieri