Skip to main content
The bomboni_proto crate provides enhanced versions of Google’s protobuf types with additional conversion methods, serde support, and integrations with popular Rust libraries.

google::protobuf Types

Any

Represents any protobuf message type.

Methods

new
fn(type_url: String, value: Vec<u8>) -> Self
Creates a new Any message with the given type URL and value.
from_msg
fn<T: Name>(message: &T) -> Result<Self, EncodeError>
Converts a protobuf message to an Any message.Returns: Result<Any, EncodeError> - Encoded Any message or encoding error
to_msg
fn<T: Default + Name>(self) -> Result<T, DecodeError>
Converts an Any message back to the original protobuf message.Returns: Result<T, DecodeError> - Decoded message or error if type URL doesn’t match

Macros

impl_proto_any_convert! - Implements TryFrom conversions between messages and Any:
impl_proto_any_convert!(MyMessage, OtherMessage);

// Enables:
let any: Any = MyMessage::default().try_into()?;
let msg: MyMessage = any.try_into()?;
impl_proto_any_serde! - Implements serde serialization for Any with type-based dispatch:
mod my_any_serde {
    impl_proto_any_serde!([MyMessage, OtherMessage]);
}

#[derive(Serialize, Deserialize)]
struct Container {
    #[serde(with = "my_any_serde")]
    any: Any,
}
impl_proto_any_seq_serde! - Implements serde for sequences of Any:
mod my_any_seq_serde {
    impl_proto_any_seq_serde!(my_any_serde);
}

Timestamp

Represents a point in time.

Methods

new
fn(seconds: i64, nanos: i32) -> Self
Creates a new Timestamp with the given seconds and nanoseconds.
normalized
fn(self) -> Self
Returns a normalized canonical format of the timestamp.Ensures nanos are in the range [0, 999999999] and handles overflow/underflow.

Conversions

From<UtcDateTime>
impl From<UtcDateTime> for Timestamp
Converts from bomboni_common::UtcDateTime
TryFrom<Timestamp>
impl TryFrom<Timestamp> for UtcDateTime
Converts to bomboni_common::UtcDateTime
From<SystemTime>
impl From<SystemTime> for Timestamp
Converts from std::time::SystemTime
chrono
Feature: chrono
When the chrono feature is enabled:
  • TryFrom<Timestamp> for DateTime<Utc>
  • From<DateTime<Utc>> for Timestamp
  • TryFrom<Timestamp> for NaiveDateTime
  • From<NaiveDateTime> for Timestamp

String Format

Display
impl Display for Timestamp
Formats as RFC3339 string (e.g., "1970-01-01T00:00:10.000000002Z")
FromStr
impl FromStr for Timestamp
Parses from RFC3339 string format

Serde

Timestamp automatically serializes/deserializes as RFC3339 strings.

Duration

Represents a time span.

Methods

new
fn(seconds: i64, nanos: i32) -> Self
Creates a new Duration with the given seconds and nanoseconds.
normalized
fn(self) -> Self
Returns a normalized canonical format of the duration.Ensures nanos have the same sign as seconds and are in the valid range.

Conversions

TryFrom<std::time::Duration>
impl TryFrom<std::time::Duration>
Converts from standard library Duration (only positive durations)
TryFrom<Duration>
impl TryFrom<Duration> for std::time::Duration
Converts to standard library Duration (fails for negative durations)
TryFrom<time::Duration>
impl TryFrom<time::Duration>
Converts from time crate Duration
chrono
Feature: chrono
When the chrono feature is enabled:
  • TryFrom<chrono::Duration> for Duration
  • TryFrom<Duration> for chrono::Duration

String Format

Display
impl Display for Duration
Formats as string with ‘s’ suffix (e.g., "10.000000002s")
FromStr
impl FromStr for Duration
Parses from string format (e.g., "10.5s")

FieldMask

Represents a field mask for partial updates.

Methods

new
fn(paths: Vec<String>) -> Self
Creates a new field mask with the given paths.
contains
fn(&self, path: &str) -> bool
Checks if this field mask contains the exact given path.
masks
fn(&self, field_path: &str) -> bool
Checks if this field mask masks the given field path.Returns true if any path in the mask is a prefix of the field path.

Conversions

From<T>
impl<T: IntoIterator<Item = impl ToString>> From<T>
Creates a FieldMask from any iterator of string-like items.Example:
let mask = FieldMask::from(["user.name", "user.email"]);

Serde

FieldMask serializes as a comma-separated string (e.g., "user.name,user.email").

Empty

Represents an empty message.
new
fn() -> Self
Creates a new empty message.

Struct and Value

Dynamic JSON-like structures.

Struct Methods

new
fn(fields: BTreeMap<String, Value>) -> Self
Creates a new struct with the given fields.

Conversions

TryFrom<serde_json::Value>
impl TryFrom<serde_json::Value> for Struct
Converts from JSON Value (must be an object)
From<Struct>
impl From<Struct> for serde_json::Value
Converts to JSON Value
From<BTreeMap/HashMap>
impl From<BTreeMap/HashMap<String, Value>>
Creates Struct from map of Values
From<BTreeMap/HashMap>
impl From<BTreeMap/HashMap<String, JsonValue>>
Creates Struct from map of JSON Values

Value Conversions

From<JsonValue>
impl From<serde_json::Value> for Value
Converts JSON values to protobuf Values
From<Value>
impl From<Value> for serde_json::Value
Converts protobuf Values to JSON

Wrappers

Wrapper types for primitive values: StringValue, Int32Value, Int64Value, UInt32Value, UInt64Value, FloatValue, DoubleValue, BoolValue, BytesValue.

Conversions

All wrappers implement From and Into for their corresponding primitive types:
let wrapper: Int32Value = 42.into();
let value: i32 = wrapper.into();

let str_wrapper: StringValue = "hello".into();
let string: String = str_wrapper.into();

String Parsing

Numeric wrappers implement FromStr:
let value: Int64Value = "42".parse()?;

Display

All wrappers implement Display for easy formatting.

google::rpc Types

Status

Represents an RPC status with code, message, and details.

Methods

new
fn(code: Code, message: String, details: Vec<Any>) -> Self
Creates a new Status with the given code, message, and error details.

Tonic Integration

When the tonic feature is enabled:
TryFrom<tonic::Status>
impl TryFrom<tonic::Status> for Status
Converts from tonic Status, decoding the details
TryFrom<Status>
impl TryFrom<Status> for tonic::Status
Converts to tonic Status, encoding the details

Serde Helpers

detail_serde module - For single Any details:
#[derive(Serialize, Deserialize)]
struct Response {
    #[serde(with = "google::rpc::status::detail_serde")]
    detail: Any,
}
details_serde module - For Vec of Any details:
#[derive(Serialize, Deserialize)]
struct Response {
    #[serde(with = "google::rpc::status::details_serde")]
    details: Vec<Any>,
}

Code

RPC status codes enum. Supported codes:
  • Ok (0)
  • Cancelled (1)
  • Unknown (2)
  • InvalidArgument (3)
  • DeadlineExceeded (4)
  • NotFound (5)
  • AlreadyExists (6)
  • PermissionDenied (7)
  • ResourceExhausted (8)
  • FailedPrecondition (9)
  • Aborted (10)
  • OutOfRange (11)
  • Unimplemented (12)
  • Internal (13)
  • Unavailable (14)
  • DataLoss (15)
  • Unauthenticated (16)

Methods

to_status_code
fn(&self) -> StatusCode
Converts RPC code to HTTP status code following Google API design guidelines.Mappings:
  • InvalidArgument, FailedPrecondition, OutOfRange → 400 BAD_REQUEST
  • Unauthenticated → 401 UNAUTHORIZED
  • PermissionDenied → 403 FORBIDDEN
  • NotFound → 404 NOT_FOUND
  • Aborted, AlreadyExists → 409 CONFLICT
  • ResourceExhausted → 429 TOO_MANY_REQUESTS
  • Cancelled → 499
  • Others → 500 INTERNAL_SERVER_ERROR

Tonic Integration

When the tonic feature is enabled:
TryFrom<tonic::Code>
impl TryFrom<tonic::Code> for Code
Converts from tonic Code
TryFrom<Code>
impl TryFrom<Code> for tonic::Code
Converts to tonic Code

Error Detail Types

The following error detail types support conversion to/from Any:
  • ErrorInfo - Additional error information with reason, domain, and metadata
  • RetryInfo - Information about when to retry
  • DebugInfo - Debug information with stack trace and detail
  • QuotaFailure - Quota violation details
  • PreconditionFailure - Precondition failure details
  • BadRequest - Bad request field violations
  • RequestInfo - Request metadata
  • ResourceInfo - Resource information
  • Help - Help links
  • LocalizedMessage - Localized error messages
All of these types have TryFrom conversions with Any:
let error_info = ErrorInfo {
    reason: "INVALID_EMAIL".to_string(),
    domain: "myapp.example.com".to_string(),
    metadata: Default::default(),
};

let any: Any = error_info.try_into()?;
let decoded: ErrorInfo = any.try_into()?;

Macros

include_proto!

Includes generated protobuf code.
include_proto!("mypackage");
// Expands to: include!(concat!(env!("OUT_DIR"), "/mypackage.rs"));

include_file_descriptor_set!

Includes generated protobuf file descriptor set.
let descriptor_bytes = include_file_descriptor_set!();
// or with custom name:
let descriptor_bytes = include_file_descriptor_set!("custom_name");

Build docs developers (and LLMs) love