konpeito 0.1.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 (180) hide show
  1. checksums.yaml +7 -0
  2. data/.ruby-version +1 -0
  3. data/CHANGELOG.md +75 -0
  4. data/CONTRIBUTING.md +123 -0
  5. data/LICENSE +21 -0
  6. data/README.md +257 -0
  7. data/Rakefile +11 -0
  8. data/bin/konpeito +6 -0
  9. data/konpeito.gemspec +43 -0
  10. data/lib/konpeito/ast/typed_ast.rb +620 -0
  11. data/lib/konpeito/ast/visitor.rb +78 -0
  12. data/lib/konpeito/cache/cache_manager.rb +230 -0
  13. data/lib/konpeito/cache/dependency_graph.rb +192 -0
  14. data/lib/konpeito/cache.rb +8 -0
  15. data/lib/konpeito/cli/base_command.rb +187 -0
  16. data/lib/konpeito/cli/build_command.rb +220 -0
  17. data/lib/konpeito/cli/check_command.rb +104 -0
  18. data/lib/konpeito/cli/config.rb +231 -0
  19. data/lib/konpeito/cli/deps_command.rb +128 -0
  20. data/lib/konpeito/cli/doctor_command.rb +340 -0
  21. data/lib/konpeito/cli/fmt_command.rb +199 -0
  22. data/lib/konpeito/cli/init_command.rb +312 -0
  23. data/lib/konpeito/cli/lsp_command.rb +40 -0
  24. data/lib/konpeito/cli/run_command.rb +150 -0
  25. data/lib/konpeito/cli/test_command.rb +248 -0
  26. data/lib/konpeito/cli/watch_command.rb +212 -0
  27. data/lib/konpeito/cli.rb +301 -0
  28. data/lib/konpeito/codegen/builtin_methods.rb +229 -0
  29. data/lib/konpeito/codegen/cruby_backend.rb +1090 -0
  30. data/lib/konpeito/codegen/debug_info.rb +352 -0
  31. data/lib/konpeito/codegen/inliner.rb +486 -0
  32. data/lib/konpeito/codegen/jvm_backend.rb +197 -0
  33. data/lib/konpeito/codegen/jvm_generator.rb +13412 -0
  34. data/lib/konpeito/codegen/llvm_generator.rb +13191 -0
  35. data/lib/konpeito/codegen/loop_optimizer.rb +363 -0
  36. data/lib/konpeito/codegen/monomorphizer.rb +359 -0
  37. data/lib/konpeito/codegen/profile_runtime.c +341 -0
  38. data/lib/konpeito/codegen/profiler.rb +99 -0
  39. data/lib/konpeito/compiler.rb +592 -0
  40. data/lib/konpeito/dependency_resolver.rb +296 -0
  41. data/lib/konpeito/diagnostics/collector.rb +127 -0
  42. data/lib/konpeito/diagnostics/diagnostic.rb +237 -0
  43. data/lib/konpeito/diagnostics/renderer.rb +144 -0
  44. data/lib/konpeito/formatter/formatter.rb +1214 -0
  45. data/lib/konpeito/hir/builder.rb +7167 -0
  46. data/lib/konpeito/hir/nodes.rb +2465 -0
  47. data/lib/konpeito/lsp/document_manager.rb +820 -0
  48. data/lib/konpeito/lsp/server.rb +183 -0
  49. data/lib/konpeito/lsp/transport.rb +38 -0
  50. data/lib/konpeito/parser/prism_adapter.rb +65 -0
  51. data/lib/konpeito/platform.rb +103 -0
  52. data/lib/konpeito/profile/report.rb +136 -0
  53. data/lib/konpeito/rbs_inline/preprocessor.rb +199 -0
  54. data/lib/konpeito/stdlib/compression/compression.rb +72 -0
  55. data/lib/konpeito/stdlib/compression/compression.rbs +60 -0
  56. data/lib/konpeito/stdlib/compression/compression_native.c +415 -0
  57. data/lib/konpeito/stdlib/compression/extconf.rb +19 -0
  58. data/lib/konpeito/stdlib/crypto/crypto.rb +85 -0
  59. data/lib/konpeito/stdlib/crypto/crypto.rbs +74 -0
  60. data/lib/konpeito/stdlib/crypto/crypto_native.c +312 -0
  61. data/lib/konpeito/stdlib/crypto/extconf.rb +40 -0
  62. data/lib/konpeito/stdlib/http/extconf.rb +19 -0
  63. data/lib/konpeito/stdlib/http/http.rb +125 -0
  64. data/lib/konpeito/stdlib/http/http.rbs +57 -0
  65. data/lib/konpeito/stdlib/http/http_native.c +440 -0
  66. data/lib/konpeito/stdlib/json/extconf.rb +17 -0
  67. data/lib/konpeito/stdlib/json/json.rb +44 -0
  68. data/lib/konpeito/stdlib/json/json.rbs +33 -0
  69. data/lib/konpeito/stdlib/json/json_native.c +286 -0
  70. data/lib/konpeito/stdlib/ui/extconf.rb +216 -0
  71. data/lib/konpeito/stdlib/ui/konpeito_ui_native.cpp +1625 -0
  72. data/lib/konpeito/stdlib/ui/konpeito_ui_native.h +162 -0
  73. data/lib/konpeito/stdlib/ui/ui.rb +318 -0
  74. data/lib/konpeito/stdlib/ui/ui.rbs +247 -0
  75. data/lib/konpeito/type_checker/annotation_parser.rb +67 -0
  76. data/lib/konpeito/type_checker/hm_inferrer.rb +2565 -0
  77. data/lib/konpeito/type_checker/inferrer.rb +565 -0
  78. data/lib/konpeito/type_checker/rbs_loader.rb +1621 -0
  79. data/lib/konpeito/type_checker/type_resolver.rb +276 -0
  80. data/lib/konpeito/type_checker/types.rb +1434 -0
  81. data/lib/konpeito/type_checker/unification.rb +323 -0
  82. data/lib/konpeito/ui/animation/animated_state.rb +80 -0
  83. data/lib/konpeito/ui/animation/easing.rb +59 -0
  84. data/lib/konpeito/ui/animation/value_tween.rb +66 -0
  85. data/lib/konpeito/ui/app.rb +379 -0
  86. data/lib/konpeito/ui/box.rb +38 -0
  87. data/lib/konpeito/ui/castella.rb +70 -0
  88. data/lib/konpeito/ui/castella_native.rb +76 -0
  89. data/lib/konpeito/ui/chart/area_chart.rb +305 -0
  90. data/lib/konpeito/ui/chart/bar_chart.rb +288 -0
  91. data/lib/konpeito/ui/chart/base_chart.rb +210 -0
  92. data/lib/konpeito/ui/chart/chart_helpers.rb +79 -0
  93. data/lib/konpeito/ui/chart/gauge_chart.rb +171 -0
  94. data/lib/konpeito/ui/chart/heatmap_chart.rb +222 -0
  95. data/lib/konpeito/ui/chart/line_chart.rb +289 -0
  96. data/lib/konpeito/ui/chart/pie_chart.rb +219 -0
  97. data/lib/konpeito/ui/chart/scales.rb +77 -0
  98. data/lib/konpeito/ui/chart/scatter_chart.rb +303 -0
  99. data/lib/konpeito/ui/chart/stacked_bar_chart.rb +276 -0
  100. data/lib/konpeito/ui/column.rb +271 -0
  101. data/lib/konpeito/ui/core.rb +2199 -0
  102. data/lib/konpeito/ui/dsl.rb +443 -0
  103. data/lib/konpeito/ui/frame.rb +171 -0
  104. data/lib/konpeito/ui/frame_native.rb +494 -0
  105. data/lib/konpeito/ui/markdown/ast.rb +124 -0
  106. data/lib/konpeito/ui/markdown/mermaid/layout.rb +387 -0
  107. data/lib/konpeito/ui/markdown/mermaid/models.rb +232 -0
  108. data/lib/konpeito/ui/markdown/mermaid/parser.rb +519 -0
  109. data/lib/konpeito/ui/markdown/mermaid/renderer.rb +336 -0
  110. data/lib/konpeito/ui/markdown/parser.rb +805 -0
  111. data/lib/konpeito/ui/markdown/renderer.rb +639 -0
  112. data/lib/konpeito/ui/markdown/theme.rb +165 -0
  113. data/lib/konpeito/ui/render_node.rb +260 -0
  114. data/lib/konpeito/ui/row.rb +207 -0
  115. data/lib/konpeito/ui/spacer.rb +18 -0
  116. data/lib/konpeito/ui/style.rb +799 -0
  117. data/lib/konpeito/ui/theme.rb +563 -0
  118. data/lib/konpeito/ui/themes/material.rb +35 -0
  119. data/lib/konpeito/ui/themes/tokyo_night.rb +6 -0
  120. data/lib/konpeito/ui/widgets/button.rb +103 -0
  121. data/lib/konpeito/ui/widgets/calendar.rb +1034 -0
  122. data/lib/konpeito/ui/widgets/checkbox.rb +119 -0
  123. data/lib/konpeito/ui/widgets/container.rb +91 -0
  124. data/lib/konpeito/ui/widgets/data_table.rb +667 -0
  125. data/lib/konpeito/ui/widgets/divider.rb +29 -0
  126. data/lib/konpeito/ui/widgets/image.rb +105 -0
  127. data/lib/konpeito/ui/widgets/input.rb +485 -0
  128. data/lib/konpeito/ui/widgets/markdown.rb +57 -0
  129. data/lib/konpeito/ui/widgets/modal.rb +163 -0
  130. data/lib/konpeito/ui/widgets/multiline_input.rb +968 -0
  131. data/lib/konpeito/ui/widgets/multiline_text.rb +180 -0
  132. data/lib/konpeito/ui/widgets/net_image.rb +100 -0
  133. data/lib/konpeito/ui/widgets/progress_bar.rb +70 -0
  134. data/lib/konpeito/ui/widgets/radio_buttons.rb +93 -0
  135. data/lib/konpeito/ui/widgets/slider.rb +133 -0
  136. data/lib/konpeito/ui/widgets/switch.rb +84 -0
  137. data/lib/konpeito/ui/widgets/tabs.rb +157 -0
  138. data/lib/konpeito/ui/widgets/text.rb +110 -0
  139. data/lib/konpeito/ui/widgets/tree.rb +426 -0
  140. data/lib/konpeito/version.rb +5 -0
  141. data/lib/konpeito.rb +109 -0
  142. data/test_native_array.rb +172 -0
  143. data/test_native_array_class.rb +197 -0
  144. data/test_native_class.rb +151 -0
  145. data/tools/konpeito-asm/build.sh +65 -0
  146. data/tools/konpeito-asm/lib/asm-9.7.1.jar +0 -0
  147. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KArray.class +0 -0
  148. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KCompression.class +0 -0
  149. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KConditionVariable.class +0 -0
  150. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KCrypto.class +0 -0
  151. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KFile.class +0 -0
  152. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KHTTP.class +0 -0
  153. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KHash.class +0 -0
  154. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KJSON$Parser.class +0 -0
  155. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KJSON.class +0 -0
  156. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KMath.class +0 -0
  157. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KRactor.class +0 -0
  158. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KRactorPort.class +0 -0
  159. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KSizedQueue.class +0 -0
  160. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KThread.class +0 -0
  161. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KTime.class +0 -0
  162. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/RubyDispatch.class +0 -0
  163. data/tools/konpeito-asm/src/ClassIntrospector.java +312 -0
  164. data/tools/konpeito-asm/src/KonpeitoAssembler.java +659 -0
  165. data/tools/konpeito-asm/src/konpeito/runtime/KArray.java +390 -0
  166. data/tools/konpeito-asm/src/konpeito/runtime/KCompression.java +168 -0
  167. data/tools/konpeito-asm/src/konpeito/runtime/KConditionVariable.java +48 -0
  168. data/tools/konpeito-asm/src/konpeito/runtime/KCrypto.java +151 -0
  169. data/tools/konpeito-asm/src/konpeito/runtime/KFile.java +100 -0
  170. data/tools/konpeito-asm/src/konpeito/runtime/KHTTP.java +113 -0
  171. data/tools/konpeito-asm/src/konpeito/runtime/KHash.java +228 -0
  172. data/tools/konpeito-asm/src/konpeito/runtime/KJSON.java +405 -0
  173. data/tools/konpeito-asm/src/konpeito/runtime/KMath.java +54 -0
  174. data/tools/konpeito-asm/src/konpeito/runtime/KRactor.java +244 -0
  175. data/tools/konpeito-asm/src/konpeito/runtime/KRactorPort.java +53 -0
  176. data/tools/konpeito-asm/src/konpeito/runtime/KSizedQueue.java +49 -0
  177. data/tools/konpeito-asm/src/konpeito/runtime/KThread.java +49 -0
  178. data/tools/konpeito-asm/src/konpeito/runtime/KTime.java +53 -0
  179. data/tools/konpeito-asm/src/konpeito/runtime/RubyDispatch.java +416 -0
  180. metadata +267 -0
@@ -0,0 +1,415 @@
1
+ /*
2
+ * Konpeito Compression stdlib - zlib wrapper
3
+ *
4
+ * Provides compression/decompression using zlib.
5
+ * Supports gzip, deflate, and raw compression.
6
+ */
7
+
8
+ #include <ruby.h>
9
+ #include <zlib.h>
10
+ #include <stdlib.h>
11
+ #include <string.h>
12
+
13
+ /* Default chunk size for compression */
14
+ #define CHUNK_SIZE 16384
15
+
16
+ /*
17
+ * Compress data using gzip format
18
+ *
19
+ * @param data [String] Data to compress
20
+ * @return [String] Gzip-compressed data
21
+ * @raise [RuntimeError] if compression fails
22
+ */
23
+ VALUE konpeito_compression_gzip(VALUE self, VALUE data) {
24
+ Check_Type(data, T_STRING);
25
+
26
+ const unsigned char *input = (const unsigned char *)RSTRING_PTR(data);
27
+ size_t input_len = RSTRING_LEN(data);
28
+
29
+ /* Allocate output buffer (worst case: input size + overhead) */
30
+ uLongf output_len = compressBound(input_len) + 18; /* gzip header/footer */
31
+ unsigned char *output = malloc(output_len);
32
+ if (!output) {
33
+ rb_raise(rb_eNoMemError, "Failed to allocate compression buffer");
34
+ return Qnil;
35
+ }
36
+
37
+ /* Initialize zlib stream for gzip */
38
+ z_stream stream;
39
+ memset(&stream, 0, sizeof(stream));
40
+
41
+ /* windowBits 15 + 16 = gzip format */
42
+ int ret = deflateInit2(&stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
43
+ 15 + 16, 8, Z_DEFAULT_STRATEGY);
44
+ if (ret != Z_OK) {
45
+ free(output);
46
+ rb_raise(rb_eRuntimeError, "Failed to initialize compression: %s",
47
+ stream.msg ? stream.msg : "unknown error");
48
+ return Qnil;
49
+ }
50
+
51
+ stream.next_in = (Bytef *)input;
52
+ stream.avail_in = (uInt)input_len;
53
+ stream.next_out = output;
54
+ stream.avail_out = (uInt)output_len;
55
+
56
+ ret = deflate(&stream, Z_FINISH);
57
+ if (ret != Z_STREAM_END) {
58
+ deflateEnd(&stream);
59
+ free(output);
60
+ rb_raise(rb_eRuntimeError, "Compression failed: %s",
61
+ stream.msg ? stream.msg : "unknown error");
62
+ return Qnil;
63
+ }
64
+
65
+ size_t compressed_len = stream.total_out;
66
+ deflateEnd(&stream);
67
+
68
+ VALUE result = rb_str_new((const char *)output, compressed_len);
69
+ free(output);
70
+
71
+ return result;
72
+ }
73
+
74
+ /*
75
+ * Decompress gzip data
76
+ *
77
+ * @param data [String] Gzip-compressed data
78
+ * @return [String] Decompressed data
79
+ * @raise [RuntimeError] if decompression fails
80
+ */
81
+ VALUE konpeito_compression_gunzip(VALUE self, VALUE data) {
82
+ Check_Type(data, T_STRING);
83
+
84
+ const unsigned char *input = (const unsigned char *)RSTRING_PTR(data);
85
+ size_t input_len = RSTRING_LEN(data);
86
+
87
+ /* Start with a reasonable output buffer size */
88
+ size_t output_size = input_len * 4;
89
+ if (output_size < CHUNK_SIZE) output_size = CHUNK_SIZE;
90
+ unsigned char *output = malloc(output_size);
91
+ if (!output) {
92
+ rb_raise(rb_eNoMemError, "Failed to allocate decompression buffer");
93
+ return Qnil;
94
+ }
95
+
96
+ /* Initialize zlib stream for gzip */
97
+ z_stream stream;
98
+ memset(&stream, 0, sizeof(stream));
99
+
100
+ /* windowBits 15 + 32 = auto-detect gzip/zlib */
101
+ int ret = inflateInit2(&stream, 15 + 32);
102
+ if (ret != Z_OK) {
103
+ free(output);
104
+ rb_raise(rb_eRuntimeError, "Failed to initialize decompression: %s",
105
+ stream.msg ? stream.msg : "unknown error");
106
+ return Qnil;
107
+ }
108
+
109
+ stream.next_in = (Bytef *)input;
110
+ stream.avail_in = (uInt)input_len;
111
+
112
+ size_t total_out = 0;
113
+
114
+ do {
115
+ /* Expand buffer if needed */
116
+ if (total_out >= output_size) {
117
+ output_size *= 2;
118
+ unsigned char *new_output = realloc(output, output_size);
119
+ if (!new_output) {
120
+ inflateEnd(&stream);
121
+ free(output);
122
+ rb_raise(rb_eNoMemError, "Failed to expand decompression buffer");
123
+ return Qnil;
124
+ }
125
+ output = new_output;
126
+ }
127
+
128
+ stream.next_out = output + total_out;
129
+ stream.avail_out = (uInt)(output_size - total_out);
130
+
131
+ ret = inflate(&stream, Z_NO_FLUSH);
132
+
133
+ if (ret == Z_NEED_DICT || ret == Z_DATA_ERROR || ret == Z_MEM_ERROR) {
134
+ inflateEnd(&stream);
135
+ free(output);
136
+ rb_raise(rb_eRuntimeError, "Decompression failed: %s",
137
+ stream.msg ? stream.msg : "data error");
138
+ return Qnil;
139
+ }
140
+
141
+ total_out = stream.total_out;
142
+
143
+ } while (ret != Z_STREAM_END);
144
+
145
+ inflateEnd(&stream);
146
+
147
+ VALUE result = rb_str_new((const char *)output, total_out);
148
+ free(output);
149
+
150
+ return result;
151
+ }
152
+
153
+ /*
154
+ * Compress data using deflate (raw zlib format, no header)
155
+ *
156
+ * @param data [String] Data to compress
157
+ * @param level [Integer] Compression level (0-9, default 6)
158
+ * @return [String] Deflate-compressed data
159
+ * @raise [RuntimeError] if compression fails
160
+ */
161
+ VALUE konpeito_compression_deflate(VALUE self, VALUE data, VALUE level) {
162
+ Check_Type(data, T_STRING);
163
+
164
+ const unsigned char *input = (const unsigned char *)RSTRING_PTR(data);
165
+ size_t input_len = RSTRING_LEN(data);
166
+ int compression_level = NIL_P(level) ? Z_DEFAULT_COMPRESSION : NUM2INT(level);
167
+
168
+ if (compression_level < 0 || compression_level > 9) {
169
+ if (compression_level != Z_DEFAULT_COMPRESSION) {
170
+ rb_raise(rb_eArgError, "Compression level must be 0-9");
171
+ return Qnil;
172
+ }
173
+ }
174
+
175
+ /* Allocate output buffer */
176
+ uLongf output_len = compressBound(input_len);
177
+ unsigned char *output = malloc(output_len);
178
+ if (!output) {
179
+ rb_raise(rb_eNoMemError, "Failed to allocate compression buffer");
180
+ return Qnil;
181
+ }
182
+
183
+ /* Initialize zlib stream for raw deflate */
184
+ z_stream stream;
185
+ memset(&stream, 0, sizeof(stream));
186
+
187
+ /* windowBits -15 = raw deflate (no zlib header) */
188
+ int ret = deflateInit2(&stream, compression_level, Z_DEFLATED,
189
+ -15, 8, Z_DEFAULT_STRATEGY);
190
+ if (ret != Z_OK) {
191
+ free(output);
192
+ rb_raise(rb_eRuntimeError, "Failed to initialize compression: %s",
193
+ stream.msg ? stream.msg : "unknown error");
194
+ return Qnil;
195
+ }
196
+
197
+ stream.next_in = (Bytef *)input;
198
+ stream.avail_in = (uInt)input_len;
199
+ stream.next_out = output;
200
+ stream.avail_out = (uInt)output_len;
201
+
202
+ ret = deflate(&stream, Z_FINISH);
203
+ if (ret != Z_STREAM_END) {
204
+ deflateEnd(&stream);
205
+ free(output);
206
+ rb_raise(rb_eRuntimeError, "Compression failed: %s",
207
+ stream.msg ? stream.msg : "unknown error");
208
+ return Qnil;
209
+ }
210
+
211
+ size_t compressed_len = stream.total_out;
212
+ deflateEnd(&stream);
213
+
214
+ VALUE result = rb_str_new((const char *)output, compressed_len);
215
+ free(output);
216
+
217
+ return result;
218
+ }
219
+
220
+ /*
221
+ * Decompress deflate data (raw zlib format, no header)
222
+ *
223
+ * @param data [String] Deflate-compressed data
224
+ * @return [String] Decompressed data
225
+ * @raise [RuntimeError] if decompression fails
226
+ */
227
+ VALUE konpeito_compression_inflate(VALUE self, VALUE data) {
228
+ Check_Type(data, T_STRING);
229
+
230
+ const unsigned char *input = (const unsigned char *)RSTRING_PTR(data);
231
+ size_t input_len = RSTRING_LEN(data);
232
+
233
+ /* Start with a reasonable output buffer size */
234
+ size_t output_size = input_len * 4;
235
+ if (output_size < CHUNK_SIZE) output_size = CHUNK_SIZE;
236
+ unsigned char *output = malloc(output_size);
237
+ if (!output) {
238
+ rb_raise(rb_eNoMemError, "Failed to allocate decompression buffer");
239
+ return Qnil;
240
+ }
241
+
242
+ /* Initialize zlib stream for raw inflate */
243
+ z_stream stream;
244
+ memset(&stream, 0, sizeof(stream));
245
+
246
+ /* windowBits -15 = raw inflate (no zlib header) */
247
+ int ret = inflateInit2(&stream, -15);
248
+ if (ret != Z_OK) {
249
+ free(output);
250
+ rb_raise(rb_eRuntimeError, "Failed to initialize decompression: %s",
251
+ stream.msg ? stream.msg : "unknown error");
252
+ return Qnil;
253
+ }
254
+
255
+ stream.next_in = (Bytef *)input;
256
+ stream.avail_in = (uInt)input_len;
257
+
258
+ size_t total_out = 0;
259
+
260
+ do {
261
+ /* Expand buffer if needed */
262
+ if (total_out >= output_size) {
263
+ output_size *= 2;
264
+ unsigned char *new_output = realloc(output, output_size);
265
+ if (!new_output) {
266
+ inflateEnd(&stream);
267
+ free(output);
268
+ rb_raise(rb_eNoMemError, "Failed to expand decompression buffer");
269
+ return Qnil;
270
+ }
271
+ output = new_output;
272
+ }
273
+
274
+ stream.next_out = output + total_out;
275
+ stream.avail_out = (uInt)(output_size - total_out);
276
+
277
+ ret = inflate(&stream, Z_NO_FLUSH);
278
+
279
+ if (ret == Z_NEED_DICT || ret == Z_DATA_ERROR || ret == Z_MEM_ERROR) {
280
+ inflateEnd(&stream);
281
+ free(output);
282
+ rb_raise(rb_eRuntimeError, "Decompression failed: %s",
283
+ stream.msg ? stream.msg : "data error");
284
+ return Qnil;
285
+ }
286
+
287
+ total_out = stream.total_out;
288
+
289
+ } while (ret != Z_STREAM_END);
290
+
291
+ inflateEnd(&stream);
292
+
293
+ VALUE result = rb_str_new((const char *)output, total_out);
294
+ free(output);
295
+
296
+ return result;
297
+ }
298
+
299
+ /*
300
+ * Compress data using zlib format (with header)
301
+ *
302
+ * @param data [String] Data to compress
303
+ * @return [String] Zlib-compressed data
304
+ * @raise [RuntimeError] if compression fails
305
+ */
306
+ VALUE konpeito_compression_zlib_compress(VALUE self, VALUE data) {
307
+ Check_Type(data, T_STRING);
308
+
309
+ const unsigned char *input = (const unsigned char *)RSTRING_PTR(data);
310
+ size_t input_len = RSTRING_LEN(data);
311
+
312
+ uLongf output_len = compressBound(input_len);
313
+ unsigned char *output = malloc(output_len);
314
+ if (!output) {
315
+ rb_raise(rb_eNoMemError, "Failed to allocate compression buffer");
316
+ return Qnil;
317
+ }
318
+
319
+ int ret = compress(output, &output_len, input, input_len);
320
+ if (ret != Z_OK) {
321
+ free(output);
322
+ rb_raise(rb_eRuntimeError, "Compression failed with code %d", ret);
323
+ return Qnil;
324
+ }
325
+
326
+ VALUE result = rb_str_new((const char *)output, output_len);
327
+ free(output);
328
+
329
+ return result;
330
+ }
331
+
332
+ /*
333
+ * Decompress zlib data (with header)
334
+ *
335
+ * @param data [String] Zlib-compressed data
336
+ * @param max_size [Integer] Maximum decompressed size (for safety)
337
+ * @return [String] Decompressed data
338
+ * @raise [RuntimeError] if decompression fails
339
+ */
340
+ VALUE konpeito_compression_zlib_decompress(VALUE self, VALUE data, VALUE max_size) {
341
+ Check_Type(data, T_STRING);
342
+
343
+ const unsigned char *input = (const unsigned char *)RSTRING_PTR(data);
344
+ size_t input_len = RSTRING_LEN(data);
345
+ size_t max_output = NIL_P(max_size) ? 100 * 1024 * 1024 : (size_t)NUM2LONG(max_size); /* 100MB default */
346
+
347
+ /* Start with estimated output size */
348
+ size_t output_size = input_len * 4;
349
+ if (output_size < CHUNK_SIZE) output_size = CHUNK_SIZE;
350
+ if (output_size > max_output) output_size = max_output;
351
+
352
+ unsigned char *output = malloc(output_size);
353
+ if (!output) {
354
+ rb_raise(rb_eNoMemError, "Failed to allocate decompression buffer");
355
+ return Qnil;
356
+ }
357
+
358
+ uLongf destLen = (uLongf)output_size;
359
+ int ret;
360
+
361
+ while (1) {
362
+ ret = uncompress(output, &destLen, input, input_len);
363
+
364
+ if (ret == Z_OK) {
365
+ break;
366
+ } else if (ret == Z_BUF_ERROR) {
367
+ /* Need bigger buffer */
368
+ output_size *= 2;
369
+ if (output_size > max_output) {
370
+ free(output);
371
+ rb_raise(rb_eRuntimeError, "Decompressed data exceeds maximum size");
372
+ return Qnil;
373
+ }
374
+ unsigned char *new_output = realloc(output, output_size);
375
+ if (!new_output) {
376
+ free(output);
377
+ rb_raise(rb_eNoMemError, "Failed to expand decompression buffer");
378
+ return Qnil;
379
+ }
380
+ output = new_output;
381
+ destLen = (uLongf)output_size;
382
+ } else {
383
+ free(output);
384
+ rb_raise(rb_eRuntimeError, "Decompression failed with code %d", ret);
385
+ return Qnil;
386
+ }
387
+ }
388
+
389
+ VALUE result = rb_str_new((const char *)output, destLen);
390
+ free(output);
391
+
392
+ return result;
393
+ }
394
+
395
+ /* Module initialization */
396
+ void Init_konpeito_compression(void) {
397
+ VALUE mKonpeitoCompression = rb_define_module("KonpeitoCompression");
398
+
399
+ /* Gzip format (RFC 1952) */
400
+ rb_define_module_function(mKonpeitoCompression, "gzip", konpeito_compression_gzip, 1);
401
+ rb_define_module_function(mKonpeitoCompression, "gunzip", konpeito_compression_gunzip, 1);
402
+
403
+ /* Raw deflate (RFC 1951) - no header */
404
+ rb_define_module_function(mKonpeitoCompression, "deflate", konpeito_compression_deflate, 2);
405
+ rb_define_module_function(mKonpeitoCompression, "inflate", konpeito_compression_inflate, 1);
406
+
407
+ /* Zlib format (RFC 1950) - with header */
408
+ rb_define_module_function(mKonpeitoCompression, "zlib_compress", konpeito_compression_zlib_compress, 1);
409
+ rb_define_module_function(mKonpeitoCompression, "zlib_decompress", konpeito_compression_zlib_decompress, 2);
410
+
411
+ /* Constants */
412
+ rb_define_const(mKonpeitoCompression, "BEST_SPEED", INT2FIX(Z_BEST_SPEED));
413
+ rb_define_const(mKonpeitoCompression, "BEST_COMPRESSION", INT2FIX(Z_BEST_COMPRESSION));
414
+ rb_define_const(mKonpeitoCompression, "DEFAULT_COMPRESSION", INT2FIX(Z_DEFAULT_COMPRESSION));
415
+ }
@@ -0,0 +1,19 @@
1
+ # extconf.rb for konpeito_compression
2
+ require 'mkmf'
3
+
4
+ # Check for zlib
5
+ unless have_library('z') && have_header('zlib.h')
6
+ abort <<~MSG
7
+ zlib is required for KonpeitoCompression.
8
+
9
+ Installation:
10
+ macOS: Usually pre-installed. If not: brew install zlib
11
+ Ubuntu: sudo apt-get install zlib1g-dev
12
+ Fedora: sudo dnf install zlib-devel
13
+ MSG
14
+ end
15
+
16
+ # Optimization flags
17
+ $CFLAGS << ' -O3'
18
+
19
+ create_makefile('konpeito_compression')
@@ -0,0 +1,85 @@
1
+ # KonpeitoCrypto - Cryptographic operations using OpenSSL
2
+ #
3
+ # This module provides cryptographic functionality using the OpenSSL library.
4
+ # It is implemented as a C extension for maximum performance.
5
+ #
6
+ # Usage:
7
+ # require 'konpeito/stdlib/crypto'
8
+ #
9
+ # # Hash functions (hex output)
10
+ # hash = KonpeitoCrypto.sha256("hello world")
11
+ # # => "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9"
12
+ #
13
+ # hash = KonpeitoCrypto.sha512("hello world")
14
+ # # => "309ecc489c12d6eb4cc40f50c902f2b4d0ed77ee511a7c7a9bcd3ca86d4cd86f..."
15
+ #
16
+ # # HMAC for message authentication
17
+ # mac = KonpeitoCrypto.hmac_sha256("secret-key", "message to authenticate")
18
+ #
19
+ # # Secure random bytes
20
+ # bytes = KonpeitoCrypto.random_bytes(32) # 32 random bytes
21
+ # hex = KonpeitoCrypto.random_hex(16) # 32 character hex string
22
+ #
23
+ # # Timing-safe comparison (for password/token verification)
24
+ # if KonpeitoCrypto.secure_compare(user_token, stored_token)
25
+ # puts "Valid token"
26
+ # end
27
+
28
+ # Try to load the native extension
29
+ begin
30
+ require_relative 'konpeito_crypto'
31
+ rescue LoadError => e
32
+ # Fallback to OpenSSL gem if native extension is not available
33
+ require 'openssl'
34
+ require 'securerandom'
35
+
36
+ module KonpeitoCrypto
37
+ class << self
38
+ def sha256(data)
39
+ OpenSSL::Digest::SHA256.hexdigest(data)
40
+ end
41
+
42
+ def sha256_binary(data)
43
+ OpenSSL::Digest::SHA256.digest(data)
44
+ end
45
+
46
+ def sha512(data)
47
+ OpenSSL::Digest::SHA512.hexdigest(data)
48
+ end
49
+
50
+ def sha512_binary(data)
51
+ OpenSSL::Digest::SHA512.digest(data)
52
+ end
53
+
54
+ def hmac_sha256(key, data)
55
+ OpenSSL::HMAC.hexdigest('SHA256', key, data)
56
+ end
57
+
58
+ def hmac_sha256_binary(key, data)
59
+ OpenSSL::HMAC.digest('SHA256', key, data)
60
+ end
61
+
62
+ def hmac_sha512(key, data)
63
+ OpenSSL::HMAC.hexdigest('SHA512', key, data)
64
+ end
65
+
66
+ def random_bytes(count)
67
+ SecureRandom.random_bytes(count)
68
+ end
69
+
70
+ def random_hex(count)
71
+ SecureRandom.hex(count)
72
+ end
73
+
74
+ def secure_compare(a, b)
75
+ return false if a.bytesize != b.bytesize
76
+
77
+ result = 0
78
+ a.bytes.zip(b.bytes) { |x, y| result |= x ^ y }
79
+ result == 0
80
+ end
81
+ end
82
+ end
83
+
84
+ warn "KonpeitoCrypto: Native extension not available, using OpenSSL gem fallback (#{e.message})"
85
+ end
@@ -0,0 +1,74 @@
1
+ # KonpeitoCrypto - Cryptographic operations using OpenSSL
2
+ #
3
+ # Usage:
4
+ # # Hash functions
5
+ # hash = KonpeitoCrypto.sha256("hello") # => "2cf24dba5fb0a30e..."
6
+ # hash = KonpeitoCrypto.sha512("hello") # => "9b71d224bd62f378..."
7
+ #
8
+ # # HMAC
9
+ # mac = KonpeitoCrypto.hmac_sha256("secret", "message")
10
+ #
11
+ # # Random bytes
12
+ # bytes = KonpeitoCrypto.random_bytes(32) # => 32 random bytes (binary)
13
+ # hex = KonpeitoCrypto.random_hex(16) # => 32 char hex string
14
+ #
15
+ # # Secure comparison (timing-attack safe)
16
+ # KonpeitoCrypto.secure_compare(hash1, hash2)
17
+
18
+ module KonpeitoCrypto
19
+ # Compute SHA256 hash (hex output)
20
+ # @param data [String] Data to hash
21
+ # @return [String] Hex-encoded SHA256 hash (64 characters)
22
+ def self.sha256: (String data) -> String
23
+
24
+ # Compute SHA256 hash (binary output)
25
+ # @param data [String] Data to hash
26
+ # @return [String] Binary SHA256 hash (32 bytes)
27
+ def self.sha256_binary: (String data) -> String
28
+
29
+ # Compute SHA512 hash (hex output)
30
+ # @param data [String] Data to hash
31
+ # @return [String] Hex-encoded SHA512 hash (128 characters)
32
+ def self.sha512: (String data) -> String
33
+
34
+ # Compute SHA512 hash (binary output)
35
+ # @param data [String] Data to hash
36
+ # @return [String] Binary SHA512 hash (64 bytes)
37
+ def self.sha512_binary: (String data) -> String
38
+
39
+ # Compute HMAC-SHA256 (hex output)
40
+ # @param key [String] Secret key
41
+ # @param data [String] Data to authenticate
42
+ # @return [String] Hex-encoded HMAC-SHA256 (64 characters)
43
+ def self.hmac_sha256: (String key, String data) -> String
44
+
45
+ # Compute HMAC-SHA256 (binary output)
46
+ # @param key [String] Secret key
47
+ # @param data [String] Data to authenticate
48
+ # @return [String] Binary HMAC-SHA256 (32 bytes)
49
+ def self.hmac_sha256_binary: (String key, String data) -> String
50
+
51
+ # Compute HMAC-SHA512 (hex output)
52
+ # @param key [String] Secret key
53
+ # @param data [String] Data to authenticate
54
+ # @return [String] Hex-encoded HMAC-SHA512 (128 characters)
55
+ def self.hmac_sha512: (String key, String data) -> String
56
+
57
+ # Generate cryptographically secure random bytes
58
+ # @param count [Integer] Number of bytes to generate
59
+ # @return [String] Binary string of random bytes
60
+ # @raise [RuntimeError] if random generation fails
61
+ def self.random_bytes: (Integer count) -> String
62
+
63
+ # Generate cryptographically secure random bytes as hex string
64
+ # @param count [Integer] Number of bytes to generate (output will be 2x this length)
65
+ # @return [String] Hex-encoded random bytes
66
+ # @raise [RuntimeError] if random generation fails
67
+ def self.random_hex: (Integer count) -> String
68
+
69
+ # Constant-time comparison of two strings (prevents timing attacks)
70
+ # @param a [String] First string
71
+ # @param b [String] Second string
72
+ # @return [bool] true if strings are equal, false otherwise
73
+ def self.secure_compare: (String a, String b) -> bool
74
+ end