imgui 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +21 -0
  3. data/README.md +273 -0
  4. data/Rakefile +97 -0
  5. data/api/v1.json +53 -0
  6. data/ext/CMakeLists.txt +128 -0
  7. data/ext/Rakefile +31 -0
  8. data/ext/backend_function_bridge.cpp +180 -0
  9. data/ext/backend_function_bridge.h +40 -0
  10. data/ext/build_cimgui.rb +59 -0
  11. data/ext/extconf.rb +25 -0
  12. data/ext/glfw_vulkan_bridge.cpp +14 -0
  13. data/ext/imgui_ruby_build_config.h +17 -0
  14. data/ext/imgui_ruby_glfw.cpp +73 -0
  15. data/ext/imgui_ruby_sdl3.cpp +70 -0
  16. data/ext/imgui_ruby_wgpu.cpp +75 -0
  17. data/ext/install_cimgui.rb +25 -0
  18. data/ext/webgpu_function_bridge.cpp +245 -0
  19. data/generator/api_emitter.rb +164 -0
  20. data/generator/emitter.rb +317 -0
  21. data/generator/generate.rb +47 -0
  22. data/generator/native-dependencies.yml +88 -0
  23. data/generator/native_dependency_lock.rb +78 -0
  24. data/generator/native_dependency_snapshot.rb +159 -0
  25. data/generator/overrides.yml +11 -0
  26. data/generator/type_mapper.rb +112 -0
  27. data/generator/update_vendor.rb +30 -0
  28. data/lib/imgui/api.rb +88 -0
  29. data/lib/imgui/api_generated.rb +1633 -0
  30. data/lib/imgui/api_support.rb +144 -0
  31. data/lib/imgui/backends/glfw.rb +75 -0
  32. data/lib/imgui/backends/opengl3.rb +44 -0
  33. data/lib/imgui/backends/sdl3.rb +133 -0
  34. data/lib/imgui/backends/wgpu.rb +176 -0
  35. data/lib/imgui/backends.rb +60 -0
  36. data/lib/imgui/draw_data.rb +43 -0
  37. data/lib/imgui/dsl.rb +311 -0
  38. data/lib/imgui/dsl_support.rb +107 -0
  39. data/lib/imgui/easy_loop.rb +25 -0
  40. data/lib/imgui/errors.rb +11 -0
  41. data/lib/imgui/fonts.rb +46 -0
  42. data/lib/imgui/io.rb +91 -0
  43. data/lib/imgui/layout.rb +138 -0
  44. data/lib/imgui/memory_pool.rb +18 -0
  45. data/lib/imgui/native/enums.rb +2251 -0
  46. data/lib/imgui/native/functions.rb +1470 -0
  47. data/lib/imgui/native/structs.rb +1926 -0
  48. data/lib/imgui/native/typedefs.rb +93 -0
  49. data/lib/imgui/native.rb +130 -0
  50. data/lib/imgui/plot/api.rb +273 -0
  51. data/lib/imgui/plot/native/enums.rb +593 -0
  52. data/lib/imgui/plot/native/functions.rb +749 -0
  53. data/lib/imgui/plot/native/structs.rb +363 -0
  54. data/lib/imgui/plot/native/typedefs.rb +79 -0
  55. data/lib/imgui/plot.rb +13 -0
  56. data/lib/imgui/struct_value.rb +33 -0
  57. data/lib/imgui/style.rb +44 -0
  58. data/lib/imgui/value.rb +104 -0
  59. data/lib/imgui/version.rb +5 -0
  60. data/lib/imgui/widgets.rb +187 -0
  61. data/lib/imgui.rb +30 -0
  62. data/rakelib/platform_gem.rake +54 -0
  63. data/rakelib/source_gem.rake +75 -0
  64. metadata +129 -0
data/lib/imgui/dsl.rb ADDED
@@ -0,0 +1,311 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ImGui
4
+ class << self
5
+ def window(title, open: nil, flags: 0, &block)
6
+ guard_context!
7
+ open_pointer = boolean_pointer(open)
8
+ run_scope(
9
+ :window,
10
+ :igEnd,
11
+ Native.igBegin(title.to_s, open_pointer, Integer(flags)),
12
+ always_close: true,
13
+ &block
14
+ )
15
+ end
16
+
17
+ def child(id, size: [0, 0], child_flags: 0, window_flags: 0, &block)
18
+ guard_context!
19
+ opened = Native.igBeginChild_Str(
20
+ id.to_s,
21
+ StructValue.vec2(size),
22
+ Integer(child_flags),
23
+ Integer(window_flags)
24
+ )
25
+ run_scope(:child, :igEndChild, opened, always_close: true, &block)
26
+ end
27
+
28
+ def child_id(id, size: [0, 0], child_flags: 0, window_flags: 0, &block)
29
+ guard_context!
30
+ opened = Native.igBeginChild_ID(
31
+ Integer(id),
32
+ StructValue.vec2(size),
33
+ Integer(child_flags),
34
+ Integer(window_flags)
35
+ )
36
+ run_scope(:child, :igEndChild, opened, always_close: true, &block)
37
+ end
38
+
39
+ def menu_bar(&block)
40
+ conditional_scope(:menu_bar, :igBeginMenuBar, :igEndMenuBar, &block)
41
+ end
42
+
43
+ def main_menu_bar(&block)
44
+ conditional_scope(:main_menu_bar, :igBeginMainMenuBar, :igEndMainMenuBar, &block)
45
+ end
46
+
47
+ def menu(label, enabled: true, &block)
48
+ conditional_scope(:menu, :igBeginMenu, :igEndMenu, label.to_s, !!enabled, &block)
49
+ end
50
+
51
+ def popup(id, flags: 0, &block)
52
+ conditional_scope(:popup, :igBeginPopup, :igEndPopup, id.to_s, Integer(flags), &block)
53
+ end
54
+
55
+ def popup_context_item(id = nil, flags: PopupFlags::MouseButtonRight, &block)
56
+ conditional_scope(
57
+ :popup,
58
+ :igBeginPopupContextItem,
59
+ :igEndPopup,
60
+ id&.to_s,
61
+ Integer(flags),
62
+ &block
63
+ )
64
+ end
65
+
66
+ def popup_context_window(id = nil, flags: PopupFlags::MouseButtonRight, &block)
67
+ conditional_scope(
68
+ :popup,
69
+ :igBeginPopupContextWindow,
70
+ :igEndPopup,
71
+ id&.to_s,
72
+ Integer(flags),
73
+ &block
74
+ )
75
+ end
76
+
77
+ def popup_context_void(id = nil, flags: PopupFlags::MouseButtonRight, &block)
78
+ conditional_scope(
79
+ :popup,
80
+ :igBeginPopupContextVoid,
81
+ :igEndPopup,
82
+ id&.to_s,
83
+ Integer(flags),
84
+ &block
85
+ )
86
+ end
87
+
88
+ def popup_modal(title, open: nil, flags: 0, &block)
89
+ conditional_scope(
90
+ :popup,
91
+ :igBeginPopupModal,
92
+ :igEndPopup,
93
+ title.to_s,
94
+ boolean_pointer(open),
95
+ Integer(flags),
96
+ &block
97
+ )
98
+ end
99
+
100
+ def combo(label, preview = nil, flags: 0, &block)
101
+ conditional_scope(:combo, :igBeginCombo, :igEndCombo, label.to_s, preview, Integer(flags), &block)
102
+ end
103
+
104
+ def combo_preview(&block)
105
+ conditional_scope(:combo_preview, :igBeginComboPreview, :igEndComboPreview, &block)
106
+ end
107
+
108
+ def list_box(label, size: [0, 0], &block)
109
+ conditional_scope(
110
+ :list_box,
111
+ :igBeginListBox,
112
+ :igEndListBox,
113
+ label.to_s,
114
+ StructValue.vec2(size),
115
+ &block
116
+ )
117
+ end
118
+
119
+ def table(id, columns, flags: 0, outer_size: [0, 0], inner_width: 0.0, &block)
120
+ conditional_scope(
121
+ :table,
122
+ :igBeginTable,
123
+ :igEndTable,
124
+ id.to_s,
125
+ Integer(columns),
126
+ Integer(flags),
127
+ StructValue.vec2(outer_size),
128
+ Float(inner_width),
129
+ &block
130
+ )
131
+ end
132
+
133
+ def tab_bar(id, flags: 0, &block)
134
+ conditional_scope(:tab_bar, :igBeginTabBar, :igEndTabBar, id.to_s, Integer(flags), &block)
135
+ end
136
+
137
+ def tab_item(label, open: nil, flags: 0, &block)
138
+ conditional_scope(
139
+ :tab_item,
140
+ :igBeginTabItem,
141
+ :igEndTabItem,
142
+ label.to_s,
143
+ boolean_pointer(open),
144
+ Integer(flags),
145
+ &block
146
+ )
147
+ end
148
+
149
+ def tooltip(&block)
150
+ conditional_scope(:tooltip, :igBeginTooltip, :igEndTooltip, &block)
151
+ end
152
+
153
+ def item_tooltip(&block)
154
+ conditional_scope(:tooltip, :igBeginItemTooltip, :igEndTooltip, &block)
155
+ end
156
+
157
+ def multi_select(flags: 0, selection_size: 0, items_count: -1, &block)
158
+ pointer_scope(
159
+ :multi_select,
160
+ :igBeginMultiSelect,
161
+ :igEndMultiSelect,
162
+ Integer(flags),
163
+ Integer(selection_size),
164
+ Integer(items_count),
165
+ &block
166
+ )
167
+ end
168
+
169
+ def tree_node(label, &block)
170
+ conditional_scope(:tree_node, :igTreeNode_Str, :igTreePop, label.to_s, &block)
171
+ end
172
+
173
+ def tree_node_ex(label, flags: 0, &block)
174
+ conditional_scope(:tree_node, :igTreeNodeEx_Str, :igTreePop, label.to_s, Integer(flags), &block)
175
+ end
176
+
177
+ def drag_drop_source(flags: 0, &block)
178
+ conditional_scope(
179
+ :drag_drop_source,
180
+ :igBeginDragDropSource,
181
+ :igEndDragDropSource,
182
+ Integer(flags),
183
+ &block
184
+ )
185
+ end
186
+
187
+ def drag_drop_target(&block)
188
+ conditional_scope(:drag_drop_target, :igBeginDragDropTarget, :igEndDragDropTarget, &block)
189
+ end
190
+
191
+ def group(&block)
192
+ void_scope(:group, :igBeginGroup, :igEndGroup, &block)
193
+ end
194
+
195
+ def disabled(disabled = true, &block)
196
+ void_scope(:disabled, :igBeginDisabled, :igEndDisabled, !!disabled, &block)
197
+ end
198
+
199
+ def font(font, &block)
200
+ push_scope(:font, :igPushFont, :igPopFont, Backends.pointer(font), &block)
201
+ end
202
+
203
+ def item_width(width, &block)
204
+ push_scope(:item_width, :igPushItemWidth, :igPopItemWidth, Float(width), &block)
205
+ end
206
+
207
+ def text_wrap_pos(position = 0.0, &block)
208
+ push_scope(:text_wrap_pos, :igPushTextWrapPos, :igPopTextWrapPos, Float(position), &block)
209
+ end
210
+
211
+ def item_flag(flag, enabled = true, &block)
212
+ push_scope(:item_flag, :igPushItemFlag, :igPopItemFlag, Integer(flag), !!enabled, &block)
213
+ end
214
+
215
+ def focus_scope(id, &block)
216
+ push_scope(:focus_scope, :igPushFocusScope, :igPopFocusScope, Integer(id), &block)
217
+ end
218
+
219
+ def clip_rect(minimum, maximum, intersect: false, &block)
220
+ push_scope(
221
+ :clip_rect,
222
+ :igPushClipRect,
223
+ :igPopClipRect,
224
+ StructValue.vec2(minimum),
225
+ StructValue.vec2(maximum),
226
+ !!intersect,
227
+ &block
228
+ )
229
+ end
230
+
231
+ def style_color(index, color)
232
+ arguments = [
233
+ :style_color,
234
+ :igPushStyleColor_Vec4,
235
+ :igPopStyleColor,
236
+ Integer(index),
237
+ StructValue.vec4(color)
238
+ ]
239
+ return push_scope(*arguments, pop_arguments: [1]) unless block_given?
240
+
241
+ push_scope(*arguments, pop_arguments: [1]) { yield }
242
+ end
243
+
244
+ def style_var(index, value)
245
+ function, native_value = if value.is_a?(Array)
246
+ [:igPushStyleVar_Vec2, StructValue.vec2(value)]
247
+ else
248
+ [:igPushStyleVar_Float, Float(value)]
249
+ end
250
+ arguments = [:style_var, function, :igPopStyleVar, Integer(index), native_value]
251
+ return push_scope(*arguments, pop_arguments: [1]) unless block_given?
252
+
253
+ push_scope(*arguments, pop_arguments: [1]) { yield }
254
+ end
255
+
256
+ def with_id(value)
257
+ guard_context!
258
+ push_id(value)
259
+ return run_pushed_scope(:id, :igPopID) unless block_given?
260
+
261
+ run_pushed_scope(:id, :igPopID) { yield }
262
+ end
263
+
264
+ def end_window
265
+ close_manual_scope(:window)
266
+ end
267
+
268
+ def end_child
269
+ close_manual_scope(:child)
270
+ end
271
+
272
+ {
273
+ end_menu_bar: :menu_bar,
274
+ end_main_menu_bar: :main_menu_bar,
275
+ end_menu: :menu,
276
+ end_popup: :popup,
277
+ end_combo: :combo,
278
+ end_combo_preview: :combo_preview,
279
+ end_list_box: :list_box,
280
+ end_table: :table,
281
+ end_tab_bar: :tab_bar,
282
+ end_tab_item: :tab_item,
283
+ end_tooltip: :tooltip,
284
+ end_multi_select: :multi_select,
285
+ tree_pop: :tree_node,
286
+ end_drag_drop_source: :drag_drop_source,
287
+ end_drag_drop_target: :drag_drop_target,
288
+ end_group: :group,
289
+ end_disabled: :disabled,
290
+ pop_font: :font,
291
+ pop_item_width: :item_width,
292
+ pop_text_wrap_pos: :text_wrap_pos,
293
+ pop_item_flag: :item_flag,
294
+ pop_focus_scope: :focus_scope,
295
+ pop_clip_rect: :clip_rect,
296
+ pop_style_color: :style_color,
297
+ pop_style_var: :style_var,
298
+ pop_id: :id
299
+ }.each do |method_name, kind|
300
+ define_method(method_name) { close_manual_scope(kind) }
301
+ end
302
+
303
+ def close_scope
304
+ scope = scope_stack.last
305
+ raise StackError, "there is no open manual scope" unless scope
306
+
307
+ close_manual_scope(scope.fetch(0))
308
+ end
309
+
310
+ end
311
+ end
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ImGui
4
+ class << self
5
+ private
6
+
7
+ def conditional_scope(kind, begin_function, end_function, *arguments, &block)
8
+ guard_context!
9
+ opened = Native.public_send(begin_function, *arguments)
10
+ run_scope(kind, end_function, opened, always_close: false, &block)
11
+ end
12
+
13
+ def void_scope(kind, begin_function, end_function, *arguments, &block)
14
+ guard_context!
15
+ Native.public_send(begin_function, *arguments)
16
+ run_scope(kind, end_function, true, always_close: true, &block)
17
+ end
18
+
19
+ def pointer_scope(kind, begin_function, end_function, *arguments, &block)
20
+ guard_context!
21
+ pointer = Native.public_send(begin_function, *arguments)
22
+ opened = !null_pointer?(pointer)
23
+ return run_scope(kind, end_function, pointer, always_close: false) unless block
24
+ return unless opened
25
+
26
+ begin
27
+ block.call(pointer)
28
+ ensure
29
+ Native.public_send(end_function)
30
+ end
31
+ end
32
+
33
+ def push_scope(kind, push_function, pop_function, *arguments, pop_arguments: [], &block)
34
+ guard_context!
35
+ Native.public_send(push_function, *arguments)
36
+ run_pushed_scope(kind, pop_function, *pop_arguments, &block)
37
+ end
38
+
39
+ def run_pushed_scope(kind, pop_function, *pop_arguments, &block)
40
+ unless block
41
+ scope_stack << [kind, pop_function, pop_arguments]
42
+ return true
43
+ end
44
+
45
+ block.call
46
+ ensure
47
+ Native.public_send(pop_function, *pop_arguments) if block
48
+ end
49
+
50
+ def run_scope(kind, end_function, opened, always_close:, &block)
51
+ should_close = always_close || opened
52
+ unless block
53
+ scope_stack << [kind, end_function] if should_close
54
+ return opened
55
+ end
56
+
57
+ return false unless should_close
58
+
59
+ begin
60
+ opened ? block.call : false
61
+ ensure
62
+ Native.public_send(end_function)
63
+ end
64
+ end
65
+
66
+ def close_manual_scope(expected_kind)
67
+ guard_context!
68
+ scope = scope_stack.pop
69
+ unless scope&.fetch(0) == expected_kind
70
+ scope_stack << scope if scope
71
+ actual = scope&.fetch(0) || "none"
72
+ raise StackError, "expected #{expected_kind} scope, found #{actual}"
73
+ end
74
+
75
+ Native.public_send(scope.fetch(1), *Array(scope[2]))
76
+ end
77
+
78
+ def scope_stack
79
+ Thread.current.thread_variable_get(:imgui_ruby_scope_stack) || begin
80
+ stack = []
81
+ Thread.current.thread_variable_set(:imgui_ruby_scope_stack, stack)
82
+ stack
83
+ end
84
+ end
85
+
86
+ def boolean_pointer(value)
87
+ return nil if value.nil?
88
+ if value.is_a?(Value)
89
+ require_value_type!(value, :bool)
90
+ return value.pointer
91
+ end
92
+
93
+ pointer = MemoryPool.pointer(:bool)
94
+ pointer.put(:bool, 0, !!value)
95
+ pointer
96
+ end
97
+
98
+ def push_id(value)
99
+ case value
100
+ when String then Native.igPushID_Str(value)
101
+ when Integer then Native.igPushID_Int(value)
102
+ when FFI::Pointer then Native.igPushID_Ptr(value)
103
+ else Native.igPushID_Ptr(FFI::Pointer.new(value.object_id))
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ImGui
4
+ class << self
5
+ def frame(platform: Backends::Glfw, renderer: Backends::OpenGL3)
6
+ renderer.new_frame
7
+ platform.new_frame
8
+ new_frame
9
+ result = yield
10
+ render
11
+ renderer.render_draw_data(draw_data)
12
+ result
13
+ end
14
+
15
+ def easy_loop(window, platform: Backends::Glfw, renderer: Backends::OpenGL3)
16
+ raise ArgumentError, "a UI block is required" unless block_given?
17
+
18
+ until window.should_close?
19
+ ::GLFW.poll_events if defined?(::GLFW) && ::GLFW.respond_to?(:poll_events)
20
+ frame(platform: platform, renderer: renderer) { yield }
21
+ window.swap_buffers if window.respond_to?(:swap_buffers)
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ImGui
4
+ class Error < StandardError; end
5
+ class LibraryLoadError < Error; end
6
+ class MissingSymbolError < Error; end
7
+ class BackendUnavailableError < Error; end
8
+ class NoContextError < Error; end
9
+ class ThreadError < Error; end
10
+ class StackError < Error; end
11
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ImGui
4
+ class Fonts
5
+ attr_reader :pointer
6
+
7
+ def initialize(pointer)
8
+ @pointer = pointer
9
+ end
10
+
11
+ def add_font_default
12
+ ImGui.__send__(:guard_context!)
13
+ Native.ImFontAtlas_AddFontDefault(pointer, nil)
14
+ end
15
+
16
+ def add_font(path, size:, glyph_ranges: nil, merge: false)
17
+ ImGui.__send__(:guard_context!)
18
+ config = merge ? Native.ImFontConfig_ImFontConfig : nil
19
+ Native::ImFontConfig.new(config)[:MergeMode] = true if config
20
+ Native.ImFontAtlas_AddFontFromFileTTF(
21
+ pointer,
22
+ File.expand_path(path),
23
+ Float(size),
24
+ config,
25
+ glyph_ranges
26
+ )
27
+ ensure
28
+ Native.ImFontConfig_destroy(config) if config
29
+ end
30
+
31
+ def add_font_jp(path, size:, merge: false)
32
+ ranges = Native.ImFontAtlas_GetGlyphRangesJapanese(pointer)
33
+ add_font(path, size: size, glyph_ranges: ranges, merge: merge)
34
+ end
35
+
36
+ def build
37
+ ImGui.__send__(:guard_context!)
38
+ Native.ImFontAtlas_Build(pointer)
39
+ end
40
+
41
+ def clear
42
+ ImGui.__send__(:guard_context!)
43
+ Native.ImFontAtlas_Clear(pointer)
44
+ end
45
+ end
46
+ end
data/lib/imgui/io.rb ADDED
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ImGui
4
+ class IO
5
+ BOOLEAN_FIELDS = %i[
6
+ want_capture_mouse want_capture_keyboard want_text_input want_set_mouse_pos
7
+ want_save_ini_settings nav_active nav_visible mouse_draw_cursor
8
+ ].freeze
9
+ INTEGER_FIELDS = %i[config_flags backend_flags metrics_render_vertices metrics_render_indices].freeze
10
+ FLOAT_FIELDS = %i[delta_time framerate font_global_scale].freeze
11
+
12
+ attr_reader :pointer
13
+
14
+ def initialize(pointer)
15
+ @pointer = pointer
16
+ @native = Native::ImGuiIO.new(pointer)
17
+ @retained_strings = {}
18
+ end
19
+
20
+ INTEGER_FIELDS.each do |field|
21
+ native_field = field.to_s.split("_").map(&:capitalize).join.to_sym
22
+ define_method(field) { @native[native_field] }
23
+ define_method("#{field}=") { |value| @native[native_field] = Integer(value) }
24
+ end
25
+
26
+ FLOAT_FIELDS.each do |field|
27
+ native_field = field.to_s.split("_").map(&:capitalize).join.to_sym
28
+ define_method(field) { @native[native_field] }
29
+ define_method("#{field}=") { |value| @native[native_field] = Float(value) }
30
+ end
31
+
32
+ BOOLEAN_FIELDS.each do |field|
33
+ native_field = field.to_s.split("_").map(&:capitalize).join.to_sym
34
+ define_method(field) { @native[native_field] }
35
+ define_method("#{field}=") { |value| @native[native_field] = !!value }
36
+ end
37
+
38
+ def display_size
39
+ StructValue.to_a(@native[:DisplaySize], 2)
40
+ end
41
+
42
+ def display_size=(value)
43
+ @native[:DisplaySize] = StructValue.vec2(value)
44
+ end
45
+
46
+ def display_framebuffer_scale
47
+ StructValue.to_a(@native[:DisplayFramebufferScale], 2)
48
+ end
49
+
50
+ def display_framebuffer_scale=(value)
51
+ @native[:DisplayFramebufferScale] = StructValue.vec2(value)
52
+ end
53
+
54
+ def fonts
55
+ @fonts ||= Fonts.new(@native[:Fonts])
56
+ end
57
+
58
+ def ini_filename
59
+ pointer = @native[:IniFilename]
60
+ pointer.null? ? nil : pointer.read_string
61
+ end
62
+
63
+ def ini_filename=(filename)
64
+ set_retained_string(:IniFilename, filename)
65
+ end
66
+
67
+ def log_filename
68
+ pointer = @native[:LogFilename]
69
+ pointer.null? ? nil : pointer.read_string
70
+ end
71
+
72
+ def log_filename=(filename)
73
+ set_retained_string(:LogFilename, filename)
74
+ end
75
+
76
+ private
77
+
78
+ def set_retained_string(field, value)
79
+ if value.nil?
80
+ @retained_strings.delete(field)
81
+ @native[field] = nil
82
+ return nil
83
+ end
84
+
85
+ memory = FFI::MemoryPointer.from_string(String(value).encode(Encoding::UTF_8))
86
+ @retained_strings[field] = memory
87
+ @native[field] = memory
88
+ value
89
+ end
90
+ end
91
+ end