protospec_build/ffi/
type_.rs

1use proc_macro2::TokenStream;
2
3use crate::{asg::{Type, TypeArgument}, PartialType, ScalarType, PartialScalarType};
4
5
6pub type ForeignTypeObj = Box<dyn ForeignType + 'static>;
7
8/// An encodable and decodable foreign type object
9/// Generally these are used to represent complexly encoded types,
10/// where there isn't a notion of smaller internal types
11/// 
12/// Good examples:
13/// Custom encoded integers (i.e. varints)
14/// UTF8 strings
15/// 
16/// Bad examples:
17/// GZIP encoded data
18/// Encrypted data
19pub trait ForeignType {
20    /// Is this type assignable from this other type?
21    /// i.e. let X: ThisType = OtherType;
22    fn assignable_from(&self, type_: &Type) -> bool;
23
24    /// Is this type assignable to this other type?
25    /// i.e. let X: OtherType = ThisType;
26    /// Generally identical to [`ForeignType::assignable_from`]
27    fn assignable_to(&self, type_: &Type) -> bool;
28
29    /// An internal modified form of [`ForeignType::assignable_from`] to provide some flexibility in type checking.
30    fn assignable_from_partial(&self, type_: &PartialType) -> bool {
31        match type_ {
32            PartialType::Type(t) => self.assignable_from(t),
33            PartialType::Any => true,
34            PartialType::Scalar(PartialScalarType::Some(scalar)) |
35            PartialType::Scalar(PartialScalarType::Defaults(scalar))
36                => self.assignable_from(&Type::Scalar(*scalar)),
37            _ => false,
38        }
39    }
40
41    /// An internal modified form of [`ForeignType::assignable_to`] to provide some flexibility in type checking.
42    fn assignable_to_partial(&self, type_: &PartialType) -> bool {
43        match type_ {
44            PartialType::Type(t) => self.assignable_to(t),
45            PartialType::Any => true,
46            PartialType::Scalar(PartialScalarType::Some(scalar)) |
47            PartialType::Scalar(PartialScalarType::Defaults(scalar))
48                => self.assignable_to(&Type::Scalar(*scalar)),
49            _ => false,
50        }
51    }
52
53    /// Emits this type as a Rust type
54    fn type_ref(&self) -> TokenStream;
55
56    /**
57     *  output code should be a term expression that:
58     *   1. the expression should read its input from an implicit identifier `reader` as a `&mut R` where R: Read
59     *   2. can read an arbitrary number of bytes from `reader`
60     *   3. returns a value of the foreign type
61    */
62    fn decoding_gen(
63        &self,
64        source: TokenStream,
65        output_ref: TokenStream,
66        arguments: Vec<TokenStream>,
67        is_async: bool,
68    ) -> TokenStream;
69
70    /**
71     * output code should be a single statement that:
72     *  1. takes an expression `field_ref` as a reference to a value of the foreign type
73     *  2. the statement should write its output to an implicit identifier `writer` as a `&mut W` where W: Write
74    */
75    fn encoding_gen(
76        &self,
77        target: TokenStream,
78        field_ref: TokenStream,
79        arguments: Vec<TokenStream>,
80        is_async: bool,
81    ) -> TokenStream;
82
83    /// All arguments that can be passed to this type to describe characteristics (i.e. string length)
84    /// All optional arguments must come at the end of the list of arguments.
85    fn arguments(&self) -> Vec<TypeArgument>;
86
87    /// If `Some`, this type can receive `auto` defined lengths during encoding
88    fn can_receive_auto(&self) -> Option<ScalarType>;
89}