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}