Skip to main content

proto_message

Attribute Macro proto_message 

Source
#[proto_message]
Expand description

Implements protobuf schema and validation features for a rust struct.

This macro will implement the following:

  • Clone
  • PartialEq
  • prost::Message
  • ProtoMessage
  • AsProtoType
  • MessagePath
  • ValidatedMessage
  • CelValue (if the cel feature is enabled)
  • A method called check_validators (compiled only with #[cfg(test)]) for verifying the correctness of the validators used in it
  • (If the skip_checks(validators) attribute is not used) A test that calls the check_validators method and panics on failure.
  • A test that checks if the oneof tags used in this message (if there are any) are correct.

If the impl is not proxied, these traits and methods will target the struct directly.

If the impl is proxied:

  • A new struct with a Proto suffix will be generated (i.e. MyMsg -> MyMsgProto) and these traits and methods will target that. An impl for ProxiedMessage will also be generated.
  • The proxy will implement MessageProxy.

To learn more about proxied implementations, visit the dedicated section.

§Examples

use protify::*;

proto_package!(MY_PKG, name = "my_pkg");
define_proto_file!(MY_FILE, name = "my_file.proto", package = MY_PKG);

#[proto_message]
pub struct Msg {
	pub id: i32,
}

// Generates the `ProxiedMsgProto` struct
#[proto_message(proxied)]
pub struct ProxiedMsg {
	pub id: i32,
}

fn main() {
	// `MessageProxy` and `ProxiedMessage` methods
	let msg = ProxiedMsgProto::default();
	let proxy = msg.into_proxy();
	let msg_again = proxy.into_message();
}

§Macro attributes

  • proxied
    • Type: Ident
    • Example: #[proto_message(proxied)]
    • Description: Creates a proxied message

§Container attributes:

  • file

    • Type: Ident
    • Example: #[proto(file = MY_FILE)]
    • Description: Assigns a specific file to this item. By default, the module_path will be inherited from the target file, and can be overridden with the module_path attribute. For more info about how to manage proto files, visit the dedicated section.
  • module_path

    • Type: literal string or module_path!
    • Example: #[proto(module_path = core::module_path!())] or #[proto(module_path = "module::path")]
    • Description: Overrides the module_path for this item, which is otherwise inherited by the assigned proto file. For more info about how to manage proto files, visit the dedicated section.
  • derive

    • Type: list of Paths
    • Example: #[proto(derive(Copy))]
    • Description: In case of a proxied impl, it specifies derives to apply to the Proto message. Shorthand for #[proto(attr(derive(..)))]
  • attr

    • Type: MetaList
    • Example: #[proto(attr(serde(default)))]
    • Description: Forwards the given metas to the proto struct. In the example above, the proto struct would receive the attribute as #[serde(default)].
  • reserved_numbers

    • Type: list of individual numbers or closed ranges
    • Example: #[proto(reserved_numbers(1, 2..10, 5000..MAX))]
    • Description: Specifies the reserved numbers for the given message. These will be skipped when automatically generating tags for each field, and copied as such in the proto files output. In order to reserve up to the maximum tag range, use the MAX ident as shown above.
  • reserved_names

    • Type: list of strings
    • Example: #[proto(reserved_names("abc", "deg"))]
    • Description: Specifies the reserved names for the given message
  • options

    • Type: Expr
    • Example: #[proto(options = vec![ my_option_1() ])]
    • Description: Specifies the options for the given message. It must resolve to an implementor of IntoIterator<Item = ProtoOption>.
  • name

    • Type: string
    • Example: #[proto(name = "abc")]
    • Description: Specifies the name of the message. Overrides the default behaviour, which uses the name of the struct.
  • parent_message

    • Type: Ident
    • Example: #[proto(parent_message = MyMsg)]
    • Description: Specifies the parent message of a nested message.
  • from_proto

    • Type: function Path or closure
    • Example: #[proto(from_proto = my_convert_fn)] or #[proto(from_proto = |v| OtherType { val: v.val })]
    • Description: Overrides the automatically generated conversion from proto to proxy.
  • into_proto

    • Type: function Path or closure
    • Example: #[proto(into_proto = my_convert_fn)] or #[proto(into_proto = |v| OtherType { val: v.val })]
    • Description: Overrides the automatically generated conversion from proxy to proto.
  • deprecated

    • Type: Ident
    • Example: #[proto(deprecated = false)] or #[deprecated]
    • Description: Marks the message as deprecated. The proto output will reflect this setting. If for some reason you want to deprecate the rust struct but not the proto message, you can use #[deprecated] along with #[proto(deprecated = false)]. Vice versa, you can deprecate the proto message only by using #[proto(deprecated = true)]
  • validate

    • Type: closure or expression, or a list of them surrounded by brackets
    • Example: #[proto(validate = |v| v.cel(my_cel_rule))] or #[proto(validate = [ CustomValidator, *STATIC_VALIDATOR ])]
    • Description: Defines the default validators for the given message. These will be executed inside the message’s own validate method, and whenever the message is used as a field in another message, along with the validators defined for each field. If a closure if used, the default CelValidator builder will be passed as the argument, and the validator will be cached in a static Lazy. If another expression is used, it must resolve to an implementor of Validator for the message.
  • skip_checks

    • Type: list of Idents
    • Example: #[proto(skip_checks(validators))]
    • Description: Disables the generation of tests. Currently, the allowed values are: - validators: disables the automatic generation of a test that checks the validity of the validators used by the message. The check_validators will still be generated and be available for manual testing.

§Field attributes

§Type Attribute

In most cases, the specific protobuf type of the field will be automatically inferred, if primitive types are used.

For special int types (such as sfixed32 or sint32), bytes, oneofs, enums and messages, it may be necessary to specify these manually.

For the scalar types, you can simply use their protobuf name (sint32, bytes), whereas for oneofs, enums and messages there are a set of special attributes.

  • message

    • Type: Ident or MetaList
    • Example: #[proto(message)] or #[proto(message(default, proxied))]
    • Description: This can be used just as a plain ident to signal that the target type is an unproxied message. Otherwise, these other attributes can be used inside parentheses: - proxied: specifies that the message is proxied, so that the proto item will contain the proxied message with the Proto suffix and not the proxy itself. Only available for proxied impls. - default: allows the message to be used without being wrapped in Option. In this case, the default conversion from proto for the field will use Default::default() if the field is None in the proto item. Only available for proxied impls. - boxed: marks the message as boxed. Automatically inferred in most cases. - (any other path): this path will be assumed to be a custom proxy for the given message. Only available for proxied impls.
  • oneof

    • Type: MetaList

    • Example: #[proto(oneof(tags(1, 2), default, proxied))]

    • Description: Marks the field as a oneof. Since oneofs are reusable, this will generate a new oneof in the output proto file belonging to the specific message where it’s being used, which will have the snake_case name of the field, or a custom name if the name attribute is used.

      All the validators being defined on the oneof will be used, and the extra ones used for this specific field will only apply to the containing message.

      All the schema settings of the original oneof such as options will be retained, and the extra ones set on the field will apply only to the specific oneof being generated for this message.

      Unlike other fields, the tags for a given oneof must be set manually, and they must match the tags of the oneof precisely. The macro will automatically generate a test that checks the accuracy of the tags.

      For more information, visit [reusing oneofs].

      Other supported attributes are:

      • proxied: specifies that the oneof is proxied, so that the proto message will contain the proxied oneof with the Proto suffix and not the proxy itself. Only available for proxied impls.
      • default: allows the oneof to be used without being wrapped in Option. In this case, the default conversion from proto for the field will use [Default::default()] if the field is None in the proto item. [Default] should be implemented for the target oneof. Only available for proxied impls.
      • (any other path): this path will be assumed to be a custom proxy for the given oneof. Only available for proxied impls.
  • enum_

    • Type: Ident or MetaList
    • Example: #[proto(enum_)] or #[proto(enum_(MyEnum))]
    • Description: Specifies that the field is a proto enum. In proxied impls, the path to the specific enum should be inferred automatically, but in direct impls, the path should be specified inside parentheses.

§Cardinality Attributes

The cardinality of the field should be inferred automatically in most cases from the given type (BTreeMap/HashMap -> map, Vec -> repeated, Option -> optional (except for messages)), but if it’s not, then it can be specified as follows:

  • repeated -> repeated(target_type_as_above)
  • optional -> optional(target_type_as_above)
  • map -> map(key_type_as_above, value_type_as_above)

§Other Attributes

  • ignore

    • Type: Ident
    • Example: #[proto(ignore)]
    • Description: Excludes the field from the proto item (only valid in proxied impls). By default, the conversion from proto to proxy for this field will use Default::default() for message fields, and NameOfOneofProto::default() for oneof variants.
  • attr

    • Type: list of Metas
    • Example: #[proto(attr(default))]
    • Description: Forwards the given metas to the proto field. In the example above, the target field would receive the attribute as #[default].
  • options

    • Type: Expr
    • Example: #[proto(options = vec![ my_option_1() ])]
    • Description: Specifies the options for the given field. It must resolve to an implementor of IntoIterator<Item = ProtoOption>.
  • name

    • Type: string
    • Example: #[proto(name = "abc")]
    • Description: Specifies the name of the field. Overrides the default behaviour, which uses the snake_case name of the field, escaping any leading r# or trailing _.
  • from_proto

    • Type: function Path or closure
    • Example: #[proto(from_proto = my_convert_fn)] or #[proto(from_proto = |v| OtherType { val: v.val })]
    • Description: Overrides the automatically generated conversion from proto to proxy. If the field is marked with ignore, a closure cannot be used.
  • into_proto

    • Type: function Path or closure
    • Example: #[proto(into_proto = my_convert_fn)] or #[proto(into_proto = |v| OtherType { val: v.val })]
    • Description: Overrides the automatically generated conversion from proxy to proto.
  • deprecated

    • Type: Ident
    • Example: #[proto(deprecated = false)] or #[deprecated]
    • Description: Marks the message as deprecated. The proto output will reflect this setting. If for some reason you want to deprecate the rust field but not the proto field, you can use #[deprecated] along with #[proto(deprecated = false)]. Vice versa, you can deprecate the proto field only by using #[proto(deprecated = true)]
  • validate

    • Type: closure or expression, or a list of them surrounded by brackets

    • Example: #[proto(validate = |v| v.cel(my_cel_rule))] or #[proto(validate = [ CustomValidator, *STATIC_VALIDATOR ])]

    • Description: Defines the validators for the given field. These will be executed inside the container’s own validate method. If a closure if used, the default validator builder for the given type will be passed as the argument, and the validator will be cached in a static Lazy (except for the OneofValidator). If another expression is used, it must resolve to an implementor of Validator for the target type.

      NOTE: For messages (or vectors/maps of such messages) and oneofs that have their own validators, they will be triggered even if no field validator is specified.

  • tag

    • Type: number
    • Example: #[proto(tag = 1)]
    • Description: Sets the protobuf tag for the given field. Tags are mandatory for oneof variants, but not for messages, where they can be automatically generated.