Skip to main content

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}