Skip to content

Commit

Permalink
feat: TypeUrl trait + Any encoding support
Browse files Browse the repository at this point in the history
As discussed in tokio-rs#299, adds a `TypeUrl` trait which associates a type URL
constant with a `Message` type.

This enables adding methods to `Any` for decoding/encoding messages:

- `Any::from_message`: encodes a given `Message`, returning `Any`.
- `Any::to_message`: decodes `Any::value` as the given `Message`, first
  validating the message type has the expected type URL.
  • Loading branch information
tarcieri committed May 17, 2023
1 parent 2037251 commit 67ec6da
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 0 deletions.
36 changes: 36 additions & 0 deletions prost-types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ use core::i64;
use core::str::FromStr;
use core::time;

use prost::alloc::borrow::ToOwned;
use prost::alloc::format;
use prost::{DecodeError, EncodeError, Message, TypeUrl};

pub use protobuf::*;

// The Protobuf `Duration` and `Timestamp` types can't delegate to the standard library equivalents
Expand All @@ -33,6 +37,38 @@ pub use protobuf::*;
const NANOS_PER_SECOND: i32 = 1_000_000_000;
const NANOS_MAX: i32 = NANOS_PER_SECOND - 1;

impl Any {
/// Serialize this message proto as [`Any`].
pub fn from_message<M>(msg: &M) -> Result<Self, EncodeError>
where
M: TypeUrl,
{
let type_url = M::TYPE_URL.to_owned();
let mut value = Vec::new();
Message::encode(msg, &mut value)?;
Ok(Any { type_url, value })
}

/// Decode the given message type `M` from [`Any`], validating that it has
/// the expected [`TypeUrl`].
pub fn to_message<M>(&self) -> Result<M, DecodeError>
where
M: Default + Sized + TypeUrl,
{
if self.type_url == M::TYPE_URL {
Ok(M::decode(&*self.value)?)
} else {
let mut err = DecodeError::new(format!(
"expected type URL: \"{}\" (got: \"{}\")",
M::TYPE_URL,
&self.type_url
));
err.push("unexpected type URL", "type_url");
Err(err)
}
}
}

impl Duration {
/// Normalizes the duration to a canonical format.
///
Expand Down
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@ pub use bytes;

mod error;
mod message;
mod type_url;
mod types;

#[doc(hidden)]
pub mod encoding;

pub use crate::error::{DecodeError, EncodeError};
pub use crate::message::Message;
pub use crate::type_url::TypeUrl;

use bytes::{Buf, BufMut};

Expand Down
19 changes: 19 additions & 0 deletions src/type_url.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//! Support for associating a type URL with a [`Message`].
use crate::Message;

/// Associate a type URL with the given [`Message]`.
pub trait TypeUrl: Message {
/// Type URL for this [`Message`]. They take the form:
///
/// ```text
/// /<package>.<TypeName>
/// ```
///
/// For example:
///
/// ```text
/// /foo.bar.baz.MyTypeName
/// ```
const TYPE_URL: &'static str;
}

0 comments on commit 67ec6da

Please sign in to comment.