cedar_policy/proto/traits.rs
1/*
2 * Copyright Cedar Contributors
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * https://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17use super::ast::ProtobufConversionError;
18
19/// Error type for protobuf decoding failures
20#[derive(Debug, thiserror::Error)]
21pub enum DecodeError {
22 /// The input buffer does not contain a valid protobuf message
23 #[error(transparent)]
24 Proto(prost::DecodeError),
25 /// The protobuf message was well-formed but its contents could not be
26 /// converted into the target Cedar type
27 #[error(transparent)]
28 Conversion(ProtobufConversionError),
29}
30
31impl From<prost::DecodeError> for DecodeError {
32 fn from(e: prost::DecodeError) -> Self {
33 Self::Proto(e)
34 }
35}
36
37impl From<ProtobufConversionError> for DecodeError {
38 fn from(e: ProtobufConversionError) -> Self {
39 Self::Conversion(e)
40 }
41}
42
43/// Trait allowing serializing and deserializing in protobuf format
44pub trait Protobuf: Sized {
45 /// Encode into protobuf format. Returns a freshly-allocated buffer containing binary data.
46 fn encode(&self) -> Vec<u8>;
47 /// Decode the binary data in `buf`, producing something of type `Self`
48 ///
49 /// # Errors
50 ///
51 /// Will return [`DecodeError::Proto`] when the input buffer does not
52 /// contain a valid protobuf message, or [`DecodeError::Conversion`] when
53 /// the message is well-formed but cannot be converted into the target type.
54 fn decode(buf: impl prost::bytes::Buf) -> Result<Self, DecodeError>;
55}
56
57/// Encode `thing` into `buf` using the protobuf format `M`
58///
59/// `Err` is only returned if `buf` has insufficient space.
60#[expect(
61 dead_code,
62 reason = "experimental feature, we might have use for this one in the future"
63)]
64pub(crate) fn encode<M: prost::Message>(
65 thing: impl Into<M>,
66 buf: &mut impl prost::bytes::BufMut,
67) -> Result<(), prost::EncodeError> {
68 thing.into().encode(buf)
69}
70
71/// Encode `thing` into a freshly-allocated buffer using the protobuf format `M`
72pub(crate) fn encode_to_vec<M: prost::Message>(thing: impl Into<M>) -> Vec<u8> {
73 thing.into().encode_to_vec()
74}
75
76use std::default::Default;
77
78/// Decode something of type `T` from `buf` using the protobuf format `M`
79#[expect(
80 dead_code,
81 reason = "available for types with infallible From conversions"
82)]
83pub(crate) fn decode<M: prost::Message + Default, T: From<M>>(
84 buf: impl prost::bytes::Buf,
85) -> Result<T, DecodeError> {
86 Ok(M::decode(buf)?.into())
87}
88
89/// Decode something of type `T` from `buf` using the protobuf format `M`,
90/// where the conversion from `M` to `T` is fallible
91pub(crate) fn try_decode<
92 M: prost::Message + Default,
93 E: Into<ProtobufConversionError>,
94 T: TryFrom<M, Error = E>,
95>(
96 buf: impl prost::bytes::Buf,
97) -> Result<T, DecodeError> {
98 M::decode(buf)?
99 .try_into()
100 .map_err(|e: E| DecodeError::Conversion(e.into()))
101}