Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP Add a 'foreign' interface to prost-derive to support scalar encodings defined outside of prost #1230

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

bickfordb
Copy link

@bickfordb bickfordb commented Jan 16, 2025

Motivation

Modern webapps make heavy use of values like UUIDs and DateTimes. These are effectively numeric/string/byte scalers. It's important to make these easy to use for productivity. These are missing support in Prost and can be represented as Message structs, but this is awkward to use with libraries like SeaORM and require unnecessary conversions between protobuf-ish structs and SeaORM structs.

  1. Due to the rules of the Rust trait system where traits can only be added in the type's package or the trait's package, 3rd party application libraries can't implement prost::Message for types likeuuid::Uuid or chrono::DateTime.
  2. UUIDs and DateTimes have many different possible encodings for different purposes. For instance, a UUID is essentially a 128 bit integer which can be encoded most compactly in 16 bytes, but is often encoded as a 36 byte string for presentation layers.
  3. This adds an extension mechanism where the encoding definition can be defined and specified via a module instead of via implementing the Message trait

Example

my-web-app/src/entity/account.rs

use prost_derive::Message;
use proto::account;
use sea_orm::entity::prelude::*;
use serde::{Deserialize, Serialize};
use uuid::Uuid;

pub mod codec {
    pub mod uuid {
       // Encode UUIDs as protobuf strings:
        pub mod simple {
            use prost::encoding::string;
            use uuid::Uuid;
            pub fn default() -> Uuid {
                Uuid::nil()
            }
            pub fn encode(tag: u32, value: &Uuid, buf: &mut impl ::prost::bytes::BufMut) {
                let s = value.to_string();
                string::encode(tag, &s, buf)
            }

            pub fn encoded_len(tag: u32, value: &Uuid) -> usize {
                let s = value.to_string();
                string::encoded_len(tag, &s)
            }
            pub fn clear(value: &mut Uuid) {
                *value = Uuid::nil()
            }
            pub fn merge(
                wire_type: ::prost::encoding::WireType,
                value: &mut Uuid,
                buf: &mut impl ::prost::bytes::Buf,
                ctx: ::prost::encoding::DecodeContext,
            ) -> Result<(), prost::DecodeError> {
                let mut s: String = "".to_string();
                string::merge(wire_type, &mut s, buf, ctx)?;
                *value = Uuid::parse_str(&s)
                    .map_err(|_| prost::DecodeError::new("failed to decode uuid string"))?;
                Ok(())
            }
        }
    }
}

#[derive(Message, Clone, Debug, PartialEq, Eq, DeriveEntityModel, Deserialize, Serialize)]
#[sea_orm(table_name = "account")]
pub struct Model {
    #[sea_orm(primary_key, auto_increment = false)]
    #[prost(codec::uuid::simple, tag = 1)]
    pub id: Uuid,
    #[sea_orm(column_type = "Text")]
    #[prost(string, tag=2)]
    pub name: String,
}
my-web-app/src/account.proto
service Accounts {
    rpc SignUp(SignUpRequest) returns (SignUpResponse) {}
}

message SignUpRequest {
 string name = 1;
 string password = 2;
}

message SignUpResponse {
    Account acccount = 1;
}

message Account { 
   string id = 1 ;
   string name = 2;
}

@bickfordb bickfordb changed the title Add a 'foreign' interface to support scalars defined outside of prost Add a 'foreign' interface to support scalar encodings defined outside of prost Jan 16, 2025
@bickfordb bickfordb changed the title Add a 'foreign' interface to support scalar encodings defined outside of prost Add a 'foreign' interface to prost-derive to support scalar encodings defined outside of prost Jan 16, 2025
@bickfordb bickfordb changed the title Add a 'foreign' interface to prost-derive to support scalar encodings defined outside of prost WIP Add a 'foreign' interface to prost-derive to support scalar encodings defined outside of prost Jan 16, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant