summaryrefslogtreecommitdiffstats
path: root/third_party/rust/uniffi_bindgen/src/bindings/ruby/templates/RustBufferBuilder.rb
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/uniffi_bindgen/src/bindings/ruby/templates/RustBufferBuilder.rb')
-rw-r--r--third_party/rust/uniffi_bindgen/src/bindings/ruby/templates/RustBufferBuilder.rb264
1 files changed, 264 insertions, 0 deletions
diff --git a/third_party/rust/uniffi_bindgen/src/bindings/ruby/templates/RustBufferBuilder.rb b/third_party/rust/uniffi_bindgen/src/bindings/ruby/templates/RustBufferBuilder.rb
new file mode 100644
index 0000000000..8749139116
--- /dev/null
+++ b/third_party/rust/uniffi_bindgen/src/bindings/ruby/templates/RustBufferBuilder.rb
@@ -0,0 +1,264 @@
+
+# Helper for structured writing of values into a RustBuffer.
+class RustBufferBuilder
+ def initialize
+ @rust_buf = RustBuffer.alloc 16
+ @rust_buf.len = 0
+ end
+
+ def finalize
+ rbuf = @rust_buf
+
+ @rust_buf = nil
+
+ rbuf
+ end
+
+ def discard
+ return if @rust_buf.nil?
+
+ rbuf = finalize
+ rbuf.free
+ end
+
+ def write(value)
+ reserve(value.bytes.size) do
+ @rust_buf.data.put_array_of_char @rust_buf.len, value.bytes
+ end
+ end
+
+ {% for typ in ci.iter_types() -%}
+ {%- let canonical_type_name = canonical_name(typ).borrow()|class_name_rb -%}
+ {%- match typ -%}
+
+ {% when Type::Int8 -%}
+
+ def write_I8(v)
+ v = {{ ci.namespace()|class_name_rb }}::uniffi_in_range(v, "i8", -2**7, 2**7)
+ pack_into(1, 'c', v)
+ end
+
+ {% when Type::UInt8 -%}
+
+ def write_U8(v)
+ v = {{ ci.namespace()|class_name_rb }}::uniffi_in_range(v, "u8", 0, 2**8)
+ pack_into(1, 'c', v)
+ end
+
+ {% when Type::Int16 -%}
+
+ def write_I16(v)
+ v = {{ ci.namespace()|class_name_rb }}::uniffi_in_range(v, "i16", -2**15, 2**15)
+ pack_into(2, 's>', v)
+ end
+
+ {% when Type::UInt16 -%}
+
+ def write_U16(v)
+ v = {{ ci.namespace()|class_name_rb }}::uniffi_in_range(v, "u16", 0, 2**16)
+ pack_into(2, 'S>', v)
+ end
+
+ {% when Type::Int32 -%}
+
+ def write_I32(v)
+ v = {{ ci.namespace()|class_name_rb }}::uniffi_in_range(v, "i32", -2**31, 2**31)
+ pack_into(4, 'l>', v)
+ end
+
+ {% when Type::UInt32 -%}
+
+ def write_U32(v)
+ v = {{ ci.namespace()|class_name_rb }}::uniffi_in_range(v, "u32", 0, 2**32)
+ pack_into(4, 'L>', v)
+ end
+
+ {% when Type::Int64 -%}
+
+ def write_I64(v)
+ v = {{ ci.namespace()|class_name_rb }}::uniffi_in_range(v, "i64", -2**63, 2**63)
+ pack_into(8, 'q>', v)
+ end
+
+ {% when Type::UInt64 -%}
+
+ def write_U64(v)
+ v = {{ ci.namespace()|class_name_rb }}::uniffi_in_range(v, "u64", 0, 2**64)
+ pack_into(8, 'Q>', v)
+ end
+
+ {% when Type::Float32 -%}
+
+ def write_F32(v)
+ pack_into(4, 'g', v)
+ end
+
+ {% when Type::Float64 -%}
+
+ def write_F64(v)
+ pack_into(8, 'G', v)
+ end
+
+ {% when Type::Boolean -%}
+
+ def write_Bool(v)
+ pack_into(1, 'c', v ? 1 : 0)
+ end
+
+ {% when Type::String -%}
+
+ def write_String(v)
+ v = {{ ci.namespace()|class_name_rb }}::uniffi_utf8(v)
+ pack_into 4, 'l>', v.bytes.size
+ write v
+ end
+
+ {% when Type::Bytes -%}
+
+ def write_Bytes(v)
+ v = {{ ci.namespace()|class_name_rb }}::uniffi_bytes(v)
+ pack_into 4, 'l>', v.bytes.size
+ write v
+ end
+
+ {% when Type::Timestamp -%}
+ # The Timestamp type.
+ ONE_SECOND_IN_NANOSECONDS = 10**9
+
+ def write_{{ canonical_type_name }}(v)
+ seconds = v.tv_sec
+ nanoseconds = v.tv_nsec
+
+ # UniFFi conventions assume that nanoseconds part has to represent nanoseconds portion of
+ # duration between epoch and the timestamp moment. Ruby `Time#tv_nsec` returns the number of
+ # nanoseconds for the subsecond part, which is sort of opposite to "duration" meaning.
+ # Hence we need to convert value returned by `Time#tv_nsec` back and forth with the following
+ # logic:
+ if seconds < 0 && nanoseconds != 0
+ # In order to get duration nsec we shift by 1 second:
+ nanoseconds = ONE_SECOND_IN_NANOSECONDS - nanoseconds
+
+ # Then we compensate 1 second shift:
+ seconds += 1
+ end
+
+ pack_into 8, 'q>', seconds
+ pack_into 4, 'L>', nanoseconds
+ end
+
+ {% when Type::Duration -%}
+ # The Duration type.
+
+ def write_{{ canonical_type_name }}(v)
+ seconds = v.tv_sec
+ nanoseconds = v.tv_nsec
+
+ raise ArgumentError, 'Invalid duration, must be non-negative' if seconds < 0
+
+ pack_into 8, 'Q>', seconds
+ pack_into 4, 'L>', nanoseconds
+ end
+
+ {% when Type::Object with { name: object_name, module_path, imp } -%}
+ # The Object type {{ object_name }}.
+
+ def write_{{ canonical_type_name }}(obj)
+ pointer = {{ object_name|class_name_rb}}._uniffi_lower obj
+ pack_into(8, 'Q>', pointer.address)
+ end
+
+ {% when Type::Enum { name: enum_name, module_path } -%}
+ {% if !ci.is_name_used_as_error(enum_name) %}
+ {%- let e = ci|get_enum_definition(enum_name) -%}
+ # The Enum type {{ enum_name }}.
+
+ def write_{{ canonical_type_name }}(v)
+ {%- if e.is_flat() %}
+ pack_into(4, 'l>', v)
+ {%- else -%}
+ {%- for variant in e.variants() %}
+ if v.{{ variant.name()|var_name_rb }}?
+ pack_into(4, 'l>', {{ loop.index }})
+ {%- for field in variant.fields() %}
+ self.write_{{ canonical_name(field.as_type().borrow()).borrow()|class_name_rb }}(v.{{ field.name() }})
+ {%- endfor %}
+ end
+ {%- endfor %}
+ {%- endif %}
+ end
+ {% endif %}
+
+ {% when Type::Record { name: record_name, module_path } -%}
+ {%- let rec = ci|get_record_definition(record_name) -%}
+ # The Record type {{ record_name }}.
+
+ def write_{{ canonical_type_name }}(v)
+ {%- for field in rec.fields() %}
+ self.write_{{ canonical_name(field.as_type().borrow()).borrow()|class_name_rb }}(v.{{ field.name()|var_name_rb }})
+ {%- endfor %}
+ end
+
+ {% when Type::Optional { inner_type } -%}
+ # The Optional<T> type for {{ canonical_name(inner_type) }}.
+
+ def write_{{ canonical_type_name }}(v)
+ if v.nil?
+ pack_into(1, 'c', 0)
+ else
+ pack_into(1, 'c', 1)
+ self.write_{{ canonical_name(inner_type).borrow()|class_name_rb }}(v)
+ end
+ end
+
+ {% when Type::Sequence { inner_type } -%}
+ # The Sequence<T> type for {{ canonical_name(inner_type) }}.
+
+ def write_{{ canonical_type_name }}(items)
+ pack_into(4, 'l>', items.size)
+
+ items.each do |item|
+ self.write_{{ canonical_name(inner_type).borrow()|class_name_rb }}(item)
+ end
+ end
+
+ {% when Type::Map { key_type: k, value_type: inner_type } -%}
+ # The Map<T> type for {{ canonical_name(inner_type) }}.
+
+ def write_{{ canonical_type_name }}(items)
+ pack_into(4, 'l>', items.size)
+
+ items.each do |k, v|
+ write_String(k)
+ self.write_{{ canonical_name(inner_type).borrow()|class_name_rb }}(v)
+ end
+ end
+
+ {%- else -%}
+ # This type is not yet supported in the Ruby backend.
+ def write_{{ canonical_type_name }}(v)
+ raise InternalError('RustBufferStream.write() not implemented yet for {{ canonical_type_name }}')
+ end
+
+ {%- endmatch -%}
+ {%- endfor %}
+
+ private
+
+ def reserve(num_bytes)
+ if @rust_buf.len + num_bytes > @rust_buf.capacity
+ @rust_buf = RustBuffer.reserve(@rust_buf, num_bytes)
+ end
+
+ yield
+
+ @rust_buf.len += num_bytes
+ end
+
+ def pack_into(size, format, value)
+ reserve(size) do
+ @rust_buf.data.put_array_of_char @rust_buf.len, [value].pack(format).bytes
+ end
+ end
+end
+
+private_constant :RustBufferBuilder