Backed out 5 changesets (bug 1890092, bug 1888683) for causing build bustages & crash...
[gecko.git] / third_party / rust / uniffi_bindgen / src / bindings / ruby / templates / RustBufferBuilder.rb
blob8749139116bf41474b003ba5bd069849d7f6f5cf
2 # Helper for structured writing of values into a RustBuffer.
3 class RustBufferBuilder
4   def initialize
5     @rust_buf = RustBuffer.alloc 16
6     @rust_buf.len = 0
7   end
9   def finalize
10     rbuf = @rust_buf
12     @rust_buf = nil
14     rbuf
15   end
17   def discard
18     return if @rust_buf.nil?
20     rbuf = finalize
21     rbuf.free
22   end
24   def write(value)
25     reserve(value.bytes.size) do
26       @rust_buf.data.put_array_of_char @rust_buf.len, value.bytes
27     end
28   end
30   {% for typ in ci.iter_types() -%}
31   {%- let canonical_type_name = canonical_name(typ).borrow()|class_name_rb -%}
32   {%- match typ -%}
34   {% when Type::Int8 -%}
36   def write_I8(v)
37     v = {{ ci.namespace()|class_name_rb }}::uniffi_in_range(v, "i8", -2**7, 2**7)
38     pack_into(1, 'c', v)
39   end
41   {% when Type::UInt8 -%}
43   def write_U8(v)
44     v = {{ ci.namespace()|class_name_rb }}::uniffi_in_range(v, "u8", 0, 2**8)
45     pack_into(1, 'c', v)
46   end
48   {% when Type::Int16 -%}
50   def write_I16(v)
51     v = {{ ci.namespace()|class_name_rb }}::uniffi_in_range(v, "i16", -2**15, 2**15)
52     pack_into(2, 's>', v)
53   end
55   {% when Type::UInt16 -%}
57   def write_U16(v)
58     v = {{ ci.namespace()|class_name_rb }}::uniffi_in_range(v, "u16", 0, 2**16)
59     pack_into(2, 'S>', v)
60   end
62   {% when Type::Int32 -%}
64   def write_I32(v)
65     v = {{ ci.namespace()|class_name_rb }}::uniffi_in_range(v, "i32", -2**31, 2**31)
66     pack_into(4, 'l>', v)
67   end
69   {% when Type::UInt32 -%}
71   def write_U32(v)
72     v = {{ ci.namespace()|class_name_rb }}::uniffi_in_range(v, "u32", 0, 2**32)
73     pack_into(4, 'L>', v)
74   end
76   {% when Type::Int64 -%}
78   def write_I64(v)
79     v = {{ ci.namespace()|class_name_rb }}::uniffi_in_range(v, "i64", -2**63, 2**63)
80     pack_into(8, 'q>', v)
81   end
83   {% when Type::UInt64 -%}
85   def write_U64(v)
86     v = {{ ci.namespace()|class_name_rb }}::uniffi_in_range(v, "u64", 0, 2**64)
87     pack_into(8, 'Q>', v)
88   end
90   {% when Type::Float32 -%}
92   def write_F32(v)
93     pack_into(4, 'g', v)
94   end
96   {% when Type::Float64 -%}
98   def write_F64(v)
99     pack_into(8, 'G', v)
100   end
102   {% when Type::Boolean -%}
104   def write_Bool(v)
105     pack_into(1, 'c', v ? 1 : 0)
106   end
108   {% when Type::String -%}
110   def write_String(v)
111     v = {{ ci.namespace()|class_name_rb }}::uniffi_utf8(v)
112     pack_into 4, 'l>', v.bytes.size
113     write v
114   end
116   {% when Type::Bytes -%}
118   def write_Bytes(v)
119     v = {{ ci.namespace()|class_name_rb }}::uniffi_bytes(v)
120     pack_into 4, 'l>', v.bytes.size
121     write v
122   end
124   {% when Type::Timestamp -%}
125   # The Timestamp type.
126   ONE_SECOND_IN_NANOSECONDS = 10**9
128   def write_{{ canonical_type_name }}(v)
129     seconds = v.tv_sec
130     nanoseconds = v.tv_nsec
132     # UniFFi conventions assume that nanoseconds part has to represent nanoseconds portion of
133     # duration between epoch and the timestamp moment. Ruby `Time#tv_nsec` returns the number of
134     # nanoseconds for the subsecond part, which is sort of opposite to "duration" meaning.
135     # Hence we need to convert value returned by `Time#tv_nsec` back and forth with the following
136     # logic:
137     if seconds < 0 && nanoseconds != 0
138       # In order to get duration nsec we shift by 1 second:
139       nanoseconds = ONE_SECOND_IN_NANOSECONDS - nanoseconds
141       # Then we compensate 1 second shift:
142       seconds += 1
143     end
145     pack_into 8, 'q>', seconds
146     pack_into 4, 'L>', nanoseconds
147   end
149   {% when Type::Duration -%}
150   # The Duration type.
152   def write_{{ canonical_type_name }}(v)
153     seconds = v.tv_sec
154     nanoseconds = v.tv_nsec
156     raise ArgumentError, 'Invalid duration, must be non-negative' if seconds < 0
158     pack_into 8, 'Q>', seconds
159     pack_into 4, 'L>', nanoseconds
160   end
162   {% when Type::Object with { name: object_name, module_path, imp } -%}
163   # The Object type {{ object_name }}.
165   def write_{{ canonical_type_name }}(obj)
166     pointer = {{ object_name|class_name_rb}}._uniffi_lower obj
167     pack_into(8, 'Q>', pointer.address)
168   end
170   {% when Type::Enum { name: enum_name, module_path } -%}
171   {% if !ci.is_name_used_as_error(enum_name) %}
172   {%- let e = ci|get_enum_definition(enum_name) -%}
173   # The Enum type {{ enum_name }}.
175   def write_{{ canonical_type_name }}(v)
176     {%- if e.is_flat() %}
177     pack_into(4, 'l>', v)
178     {%- else -%}
179     {%- for variant in e.variants() %}
180     if v.{{ variant.name()|var_name_rb }}?
181       pack_into(4, 'l>', {{ loop.index }})
182       {%- for field in variant.fields() %}
183       self.write_{{ canonical_name(field.as_type().borrow()).borrow()|class_name_rb }}(v.{{ field.name() }})
184       {%- endfor %}
185     end
186     {%- endfor %}
187     {%- endif %}
188  end
189    {% endif %}
191   {% when Type::Record { name: record_name, module_path } -%}
192   {%- let rec = ci|get_record_definition(record_name) -%}
193   # The Record type {{ record_name }}.
195   def write_{{ canonical_type_name }}(v)
196     {%- for field in rec.fields() %}
197     self.write_{{ canonical_name(field.as_type().borrow()).borrow()|class_name_rb }}(v.{{ field.name()|var_name_rb }})
198     {%- endfor %}
199   end
201   {% when Type::Optional { inner_type } -%}
202   # The Optional<T> type for {{ canonical_name(inner_type) }}.
204   def write_{{ canonical_type_name }}(v)
205     if v.nil?
206       pack_into(1, 'c', 0)
207     else
208       pack_into(1, 'c', 1)
209       self.write_{{ canonical_name(inner_type).borrow()|class_name_rb }}(v)
210     end
211   end
213   {% when Type::Sequence { inner_type } -%}
214   # The Sequence<T> type for {{ canonical_name(inner_type) }}.
216   def write_{{ canonical_type_name }}(items)
217     pack_into(4, 'l>', items.size)
219     items.each do |item|
220       self.write_{{ canonical_name(inner_type).borrow()|class_name_rb }}(item)
221     end
222   end
224   {% when Type::Map { key_type: k, value_type: inner_type } -%}
225   # The Map<T> type for {{ canonical_name(inner_type) }}.
227   def write_{{ canonical_type_name }}(items)
228     pack_into(4, 'l>', items.size)
230     items.each do |k, v|
231       write_String(k)
232       self.write_{{ canonical_name(inner_type).borrow()|class_name_rb }}(v)
233     end
234   end
236   {%- else -%}
237   # This type is not yet supported in the Ruby backend.
238   def write_{{ canonical_type_name }}(v)
239     raise InternalError('RustBufferStream.write() not implemented yet for {{ canonical_type_name }}')
240   end
242   {%- endmatch -%}
243   {%- endfor %}
245   private
247   def reserve(num_bytes)
248     if @rust_buf.len + num_bytes > @rust_buf.capacity
249       @rust_buf = RustBuffer.reserve(@rust_buf, num_bytes)
250     end
252     yield
254     @rust_buf.len += num_bytes
255   end
257   def pack_into(size, format, value)
258     reserve(size) do
259       @rust_buf.data.put_array_of_char @rust_buf.len, [value].pack(format).bytes
260     end
261   end
264 private_constant :RustBufferBuilder