2 # Helper for structured writing of values into a RustBuffer.
3 class RustBufferBuilder
5 @rust_buf = RustBuffer.alloc 16
18 return if @rust_buf.nil?
25 reserve(value.bytes.size) do
26 @rust_buf.data.put_array_of_char @rust_buf.len, value.bytes
30 {% for typ in ci.iter_types() -%}
31 {%- let canonical_type_name = canonical_name(typ).borrow()|class_name_rb -%}
34 {% when Type::Int8 -%}
37 v = {{ ci.namespace()|class_name_rb }}::uniffi_in_range(v, "i8", -2**7, 2**7)
41 {% when Type::UInt8 -%}
44 v = {{ ci.namespace()|class_name_rb }}::uniffi_in_range(v, "u8", 0, 2**8)
48 {% when Type::Int16 -%}
51 v = {{ ci.namespace()|class_name_rb }}::uniffi_in_range(v, "i16", -2**15, 2**15)
55 {% when Type::UInt16 -%}
58 v = {{ ci.namespace()|class_name_rb }}::uniffi_in_range(v, "u16", 0, 2**16)
62 {% when Type::Int32 -%}
65 v = {{ ci.namespace()|class_name_rb }}::uniffi_in_range(v, "i32", -2**31, 2**31)
69 {% when Type::UInt32 -%}
72 v = {{ ci.namespace()|class_name_rb }}::uniffi_in_range(v, "u32", 0, 2**32)
76 {% when Type::Int64 -%}
79 v = {{ ci.namespace()|class_name_rb }}::uniffi_in_range(v, "i64", -2**63, 2**63)
83 {% when Type::UInt64 -%}
86 v = {{ ci.namespace()|class_name_rb }}::uniffi_in_range(v, "u64", 0, 2**64)
90 {% when Type::Float32 -%}
96 {% when Type::Float64 -%}
102 {% when Type::Boolean -%}
105 pack_into(1, 'c', v ? 1 : 0)
108 {% when Type::String -%}
111 v = {{ ci.namespace()|class_name_rb }}::uniffi_utf8(v)
112 pack_into 4, 'l>', v.bytes.size
116 {% when Type::Bytes -%}
119 v = {{ ci.namespace()|class_name_rb }}::uniffi_bytes(v)
120 pack_into 4, 'l>', v.bytes.size
124 {% when Type::Timestamp -%}
125 # The Timestamp type.
126 ONE_SECOND_IN_NANOSECONDS = 10**9
128 def write_{{ canonical_type_name }}(v)
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
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:
145 pack_into 8, 'q>', seconds
146 pack_into 4, 'L>', nanoseconds
149 {% when Type::Duration -%}
152 def write_{{ canonical_type_name }}(v)
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
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)
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)
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() }})
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 }})
201 {% when Type::Optional { inner_type } -%}
202 # The Optional<T> type for {{ canonical_name(inner_type) }}.
204 def write_{{ canonical_type_name }}(v)
209 self.write_{{ canonical_name(inner_type).borrow()|class_name_rb }}(v)
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)
220 self.write_{{ canonical_name(inner_type).borrow()|class_name_rb }}(item)
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)
232 self.write_{{ canonical_name(inner_type).borrow()|class_name_rb }}(v)
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 }}')
247 def reserve(num_bytes)
248 if @rust_buf.len + num_bytes > @rust_buf.capacity
249 @rust_buf = RustBuffer.reserve(@rust_buf, num_bytes)
254 @rust_buf.len += num_bytes
257 def pack_into(size, format, value)
259 @rust_buf.data.put_array_of_char @rust_buf.len, [value].pack(format).bytes
264 private_constant :RustBufferBuilder