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.
- checksums.yaml +7 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +75 -0
- data/CONTRIBUTING.md +123 -0
- data/LICENSE +21 -0
- data/README.md +257 -0
- data/Rakefile +11 -0
- data/bin/konpeito +6 -0
- data/konpeito.gemspec +43 -0
- data/lib/konpeito/ast/typed_ast.rb +620 -0
- data/lib/konpeito/ast/visitor.rb +78 -0
- data/lib/konpeito/cache/cache_manager.rb +230 -0
- data/lib/konpeito/cache/dependency_graph.rb +192 -0
- data/lib/konpeito/cache.rb +8 -0
- data/lib/konpeito/cli/base_command.rb +187 -0
- data/lib/konpeito/cli/build_command.rb +220 -0
- data/lib/konpeito/cli/check_command.rb +104 -0
- data/lib/konpeito/cli/config.rb +231 -0
- data/lib/konpeito/cli/deps_command.rb +128 -0
- data/lib/konpeito/cli/doctor_command.rb +340 -0
- data/lib/konpeito/cli/fmt_command.rb +199 -0
- data/lib/konpeito/cli/init_command.rb +312 -0
- data/lib/konpeito/cli/lsp_command.rb +40 -0
- data/lib/konpeito/cli/run_command.rb +150 -0
- data/lib/konpeito/cli/test_command.rb +248 -0
- data/lib/konpeito/cli/watch_command.rb +212 -0
- data/lib/konpeito/cli.rb +301 -0
- data/lib/konpeito/codegen/builtin_methods.rb +229 -0
- data/lib/konpeito/codegen/cruby_backend.rb +1090 -0
- data/lib/konpeito/codegen/debug_info.rb +352 -0
- data/lib/konpeito/codegen/inliner.rb +486 -0
- data/lib/konpeito/codegen/jvm_backend.rb +197 -0
- data/lib/konpeito/codegen/jvm_generator.rb +13412 -0
- data/lib/konpeito/codegen/llvm_generator.rb +13191 -0
- data/lib/konpeito/codegen/loop_optimizer.rb +363 -0
- data/lib/konpeito/codegen/monomorphizer.rb +359 -0
- data/lib/konpeito/codegen/profile_runtime.c +341 -0
- data/lib/konpeito/codegen/profiler.rb +99 -0
- data/lib/konpeito/compiler.rb +592 -0
- data/lib/konpeito/dependency_resolver.rb +296 -0
- data/lib/konpeito/diagnostics/collector.rb +127 -0
- data/lib/konpeito/diagnostics/diagnostic.rb +237 -0
- data/lib/konpeito/diagnostics/renderer.rb +144 -0
- data/lib/konpeito/formatter/formatter.rb +1214 -0
- data/lib/konpeito/hir/builder.rb +7167 -0
- data/lib/konpeito/hir/nodes.rb +2465 -0
- data/lib/konpeito/lsp/document_manager.rb +820 -0
- data/lib/konpeito/lsp/server.rb +183 -0
- data/lib/konpeito/lsp/transport.rb +38 -0
- data/lib/konpeito/parser/prism_adapter.rb +65 -0
- data/lib/konpeito/platform.rb +103 -0
- data/lib/konpeito/profile/report.rb +136 -0
- data/lib/konpeito/rbs_inline/preprocessor.rb +199 -0
- data/lib/konpeito/stdlib/compression/compression.rb +72 -0
- data/lib/konpeito/stdlib/compression/compression.rbs +60 -0
- data/lib/konpeito/stdlib/compression/compression_native.c +415 -0
- data/lib/konpeito/stdlib/compression/extconf.rb +19 -0
- data/lib/konpeito/stdlib/crypto/crypto.rb +85 -0
- data/lib/konpeito/stdlib/crypto/crypto.rbs +74 -0
- data/lib/konpeito/stdlib/crypto/crypto_native.c +312 -0
- data/lib/konpeito/stdlib/crypto/extconf.rb +40 -0
- data/lib/konpeito/stdlib/http/extconf.rb +19 -0
- data/lib/konpeito/stdlib/http/http.rb +125 -0
- data/lib/konpeito/stdlib/http/http.rbs +57 -0
- data/lib/konpeito/stdlib/http/http_native.c +440 -0
- data/lib/konpeito/stdlib/json/extconf.rb +17 -0
- data/lib/konpeito/stdlib/json/json.rb +44 -0
- data/lib/konpeito/stdlib/json/json.rbs +33 -0
- data/lib/konpeito/stdlib/json/json_native.c +286 -0
- data/lib/konpeito/stdlib/ui/extconf.rb +216 -0
- data/lib/konpeito/stdlib/ui/konpeito_ui_native.cpp +1625 -0
- data/lib/konpeito/stdlib/ui/konpeito_ui_native.h +162 -0
- data/lib/konpeito/stdlib/ui/ui.rb +318 -0
- data/lib/konpeito/stdlib/ui/ui.rbs +247 -0
- data/lib/konpeito/type_checker/annotation_parser.rb +67 -0
- data/lib/konpeito/type_checker/hm_inferrer.rb +2565 -0
- data/lib/konpeito/type_checker/inferrer.rb +565 -0
- data/lib/konpeito/type_checker/rbs_loader.rb +1621 -0
- data/lib/konpeito/type_checker/type_resolver.rb +276 -0
- data/lib/konpeito/type_checker/types.rb +1434 -0
- data/lib/konpeito/type_checker/unification.rb +323 -0
- data/lib/konpeito/ui/animation/animated_state.rb +80 -0
- data/lib/konpeito/ui/animation/easing.rb +59 -0
- data/lib/konpeito/ui/animation/value_tween.rb +66 -0
- data/lib/konpeito/ui/app.rb +379 -0
- data/lib/konpeito/ui/box.rb +38 -0
- data/lib/konpeito/ui/castella.rb +70 -0
- data/lib/konpeito/ui/castella_native.rb +76 -0
- data/lib/konpeito/ui/chart/area_chart.rb +305 -0
- data/lib/konpeito/ui/chart/bar_chart.rb +288 -0
- data/lib/konpeito/ui/chart/base_chart.rb +210 -0
- data/lib/konpeito/ui/chart/chart_helpers.rb +79 -0
- data/lib/konpeito/ui/chart/gauge_chart.rb +171 -0
- data/lib/konpeito/ui/chart/heatmap_chart.rb +222 -0
- data/lib/konpeito/ui/chart/line_chart.rb +289 -0
- data/lib/konpeito/ui/chart/pie_chart.rb +219 -0
- data/lib/konpeito/ui/chart/scales.rb +77 -0
- data/lib/konpeito/ui/chart/scatter_chart.rb +303 -0
- data/lib/konpeito/ui/chart/stacked_bar_chart.rb +276 -0
- data/lib/konpeito/ui/column.rb +271 -0
- data/lib/konpeito/ui/core.rb +2199 -0
- data/lib/konpeito/ui/dsl.rb +443 -0
- data/lib/konpeito/ui/frame.rb +171 -0
- data/lib/konpeito/ui/frame_native.rb +494 -0
- data/lib/konpeito/ui/markdown/ast.rb +124 -0
- data/lib/konpeito/ui/markdown/mermaid/layout.rb +387 -0
- data/lib/konpeito/ui/markdown/mermaid/models.rb +232 -0
- data/lib/konpeito/ui/markdown/mermaid/parser.rb +519 -0
- data/lib/konpeito/ui/markdown/mermaid/renderer.rb +336 -0
- data/lib/konpeito/ui/markdown/parser.rb +805 -0
- data/lib/konpeito/ui/markdown/renderer.rb +639 -0
- data/lib/konpeito/ui/markdown/theme.rb +165 -0
- data/lib/konpeito/ui/render_node.rb +260 -0
- data/lib/konpeito/ui/row.rb +207 -0
- data/lib/konpeito/ui/spacer.rb +18 -0
- data/lib/konpeito/ui/style.rb +799 -0
- data/lib/konpeito/ui/theme.rb +563 -0
- data/lib/konpeito/ui/themes/material.rb +35 -0
- data/lib/konpeito/ui/themes/tokyo_night.rb +6 -0
- data/lib/konpeito/ui/widgets/button.rb +103 -0
- data/lib/konpeito/ui/widgets/calendar.rb +1034 -0
- data/lib/konpeito/ui/widgets/checkbox.rb +119 -0
- data/lib/konpeito/ui/widgets/container.rb +91 -0
- data/lib/konpeito/ui/widgets/data_table.rb +667 -0
- data/lib/konpeito/ui/widgets/divider.rb +29 -0
- data/lib/konpeito/ui/widgets/image.rb +105 -0
- data/lib/konpeito/ui/widgets/input.rb +485 -0
- data/lib/konpeito/ui/widgets/markdown.rb +57 -0
- data/lib/konpeito/ui/widgets/modal.rb +163 -0
- data/lib/konpeito/ui/widgets/multiline_input.rb +968 -0
- data/lib/konpeito/ui/widgets/multiline_text.rb +180 -0
- data/lib/konpeito/ui/widgets/net_image.rb +100 -0
- data/lib/konpeito/ui/widgets/progress_bar.rb +70 -0
- data/lib/konpeito/ui/widgets/radio_buttons.rb +93 -0
- data/lib/konpeito/ui/widgets/slider.rb +133 -0
- data/lib/konpeito/ui/widgets/switch.rb +84 -0
- data/lib/konpeito/ui/widgets/tabs.rb +157 -0
- data/lib/konpeito/ui/widgets/text.rb +110 -0
- data/lib/konpeito/ui/widgets/tree.rb +426 -0
- data/lib/konpeito/version.rb +5 -0
- data/lib/konpeito.rb +109 -0
- data/test_native_array.rb +172 -0
- data/test_native_array_class.rb +197 -0
- data/test_native_class.rb +151 -0
- data/tools/konpeito-asm/build.sh +65 -0
- data/tools/konpeito-asm/lib/asm-9.7.1.jar +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KArray.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KCompression.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KConditionVariable.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KCrypto.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KFile.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KHTTP.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KHash.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KJSON$Parser.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KJSON.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KMath.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KRactor.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KRactorPort.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KSizedQueue.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KThread.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KTime.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/RubyDispatch.class +0 -0
- data/tools/konpeito-asm/src/ClassIntrospector.java +312 -0
- data/tools/konpeito-asm/src/KonpeitoAssembler.java +659 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KArray.java +390 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KCompression.java +168 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KConditionVariable.java +48 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KCrypto.java +151 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KFile.java +100 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KHTTP.java +113 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KHash.java +228 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KJSON.java +405 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KMath.java +54 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KRactor.java +244 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KRactorPort.java +53 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KSizedQueue.java +49 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KThread.java +49 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KTime.java +53 -0
- data/tools/konpeito-asm/src/konpeito/runtime/RubyDispatch.java +416 -0
- metadata +267 -0
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rbs/inline"
|
|
4
|
+
|
|
5
|
+
module Konpeito
|
|
6
|
+
module RBSInline
|
|
7
|
+
# Extracts inline RBS annotations from Ruby source and generates RBS files
|
|
8
|
+
# Uses rbs-inline to generate base RBS, then merges Konpeito-specific annotations
|
|
9
|
+
#
|
|
10
|
+
# Supported annotations in Ruby source:
|
|
11
|
+
# # rbs_inline: enabled (required magic comment)
|
|
12
|
+
# # @rbs %a{native} (Konpeito annotation on class/module)
|
|
13
|
+
# # @rbs %a{cfunc: "sin"} (Konpeito annotation on method)
|
|
14
|
+
# # @rbs @x: Float (instance variable type - standard rbs-inline)
|
|
15
|
+
# #: (Float) -> Float (method type - standard rbs-inline)
|
|
16
|
+
class Preprocessor
|
|
17
|
+
# Check if a Ruby source file has inline RBS annotations
|
|
18
|
+
# @param source [String] Ruby source code
|
|
19
|
+
# @return [Boolean]
|
|
20
|
+
def self.has_inline_rbs?(source)
|
|
21
|
+
source.include?("# rbs_inline: enabled")
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Process a Ruby source file and generate RBS content with Konpeito annotations
|
|
25
|
+
# @param source [String] Ruby source code
|
|
26
|
+
# @param filename [String] Source filename for error messages
|
|
27
|
+
# @return [String] Generated RBS content with Konpeito annotations merged
|
|
28
|
+
def process(source, filename: "(inline)")
|
|
29
|
+
@source = source
|
|
30
|
+
@filename = filename
|
|
31
|
+
|
|
32
|
+
# Step 1: Extract Konpeito-specific annotations (# @rbs %a{...})
|
|
33
|
+
konpeito_annotations = extract_konpeito_annotations(source)
|
|
34
|
+
|
|
35
|
+
# Step 2: Run rbs-inline to generate base RBS
|
|
36
|
+
base_rbs = run_rbs_inline(source, filename)
|
|
37
|
+
|
|
38
|
+
# Step 3: Merge Konpeito annotations into generated RBS
|
|
39
|
+
merge_annotations(base_rbs, konpeito_annotations)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
# Extract # @rbs %a{...} annotations and their target declarations
|
|
45
|
+
# Returns a hash of { "ClassName" => [annotations], "ClassName#method" => [annotations] }
|
|
46
|
+
def extract_konpeito_annotations(source)
|
|
47
|
+
annotations = {}
|
|
48
|
+
lines = source.lines
|
|
49
|
+
pending_annotations = []
|
|
50
|
+
|
|
51
|
+
lines.each_with_index do |line, idx|
|
|
52
|
+
stripped = line.strip
|
|
53
|
+
|
|
54
|
+
# Collect Konpeito annotations
|
|
55
|
+
if stripped.start_with?("# @rbs %a{")
|
|
56
|
+
if match = stripped.match(/^#\s*@rbs\s+(%a\{[^}]+\})/)
|
|
57
|
+
pending_annotations << match[1]
|
|
58
|
+
end
|
|
59
|
+
# Match class definition
|
|
60
|
+
elsif stripped.match?(/^class\s+(\w+)/)
|
|
61
|
+
if match = stripped.match(/^class\s+(\w+)/)
|
|
62
|
+
class_name = match[1]
|
|
63
|
+
annotations[class_name] = pending_annotations.dup unless pending_annotations.empty?
|
|
64
|
+
pending_annotations.clear
|
|
65
|
+
end
|
|
66
|
+
# Match module definition
|
|
67
|
+
elsif stripped.match?(/^module\s+(\w+)/)
|
|
68
|
+
if match = stripped.match(/^module\s+(\w+)/)
|
|
69
|
+
module_name = match[1]
|
|
70
|
+
annotations[module_name] = pending_annotations.dup unless pending_annotations.empty?
|
|
71
|
+
pending_annotations.clear
|
|
72
|
+
end
|
|
73
|
+
# Match method definition
|
|
74
|
+
elsif stripped.match?(/^def\s+(self\.)?(\w+[?!=]?)/)
|
|
75
|
+
if match = stripped.match(/^def\s+(self\.)?(\w+[?!=]?)/)
|
|
76
|
+
# Find the current class/module context by looking back
|
|
77
|
+
context = find_current_context(lines, idx)
|
|
78
|
+
if context
|
|
79
|
+
singleton = match[1] ? "." : "#"
|
|
80
|
+
method_name = match[2]
|
|
81
|
+
key = "#{context}#{singleton}#{method_name}"
|
|
82
|
+
annotations[key] = pending_annotations.dup unless pending_annotations.empty?
|
|
83
|
+
end
|
|
84
|
+
pending_annotations.clear
|
|
85
|
+
end
|
|
86
|
+
# Clear pending on non-annotation, non-empty lines
|
|
87
|
+
elsif !stripped.empty? && !stripped.start_with?("#")
|
|
88
|
+
pending_annotations.clear
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
annotations
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Find the class/module context for a given line
|
|
96
|
+
def find_current_context(lines, current_idx)
|
|
97
|
+
indent_stack = []
|
|
98
|
+
|
|
99
|
+
(0...current_idx).each do |idx|
|
|
100
|
+
line = lines[idx]
|
|
101
|
+
stripped = line.strip
|
|
102
|
+
|
|
103
|
+
if stripped.match?(/^class\s+(\w+)/)
|
|
104
|
+
match = stripped.match(/^class\s+(\w+)/)
|
|
105
|
+
indent_stack << match[1]
|
|
106
|
+
elsif stripped.match?(/^module\s+(\w+)/)
|
|
107
|
+
match = stripped.match(/^module\s+(\w+)/)
|
|
108
|
+
indent_stack << match[1]
|
|
109
|
+
elsif stripped == "end"
|
|
110
|
+
indent_stack.pop
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
indent_stack.last
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# Run rbs-inline as library to generate base RBS (no subprocess)
|
|
118
|
+
def run_rbs_inline(source, _filename)
|
|
119
|
+
prism_result = Prism.parse(source)
|
|
120
|
+
parsed = RBS::Inline::Parser.parse(prism_result, opt_in: true)
|
|
121
|
+
return "" unless parsed
|
|
122
|
+
|
|
123
|
+
uses, decls, rbs_decls = parsed
|
|
124
|
+
writer = RBS::Inline::Writer.new
|
|
125
|
+
writer.write(uses, decls, rbs_decls)
|
|
126
|
+
writer.output || ""
|
|
127
|
+
rescue => e
|
|
128
|
+
warn "Warning: rbs-inline failed for #{_filename}: #{e.message}"
|
|
129
|
+
""
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# Merge Konpeito annotations into generated RBS
|
|
133
|
+
def merge_annotations(rbs_content, konpeito_annotations)
|
|
134
|
+
# First, clean up rbs-inline output (remove # @rbs comments and duplicate %a{})
|
|
135
|
+
cleaned_lines = []
|
|
136
|
+
rbs_content.lines.each do |line|
|
|
137
|
+
stripped = line.strip
|
|
138
|
+
# Skip comment lines with @rbs or redundant %a{} lines from rbs-inline
|
|
139
|
+
next if stripped.start_with?("# @rbs")
|
|
140
|
+
next if stripped.start_with?("# :")
|
|
141
|
+
next if stripped.match?(/^%a\{[^}]+\}$/) && !stripped.match?(/^%a\{(deprecated|pure)/)
|
|
142
|
+
cleaned_lines << line
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
return cleaned_lines.join if konpeito_annotations.empty?
|
|
146
|
+
|
|
147
|
+
lines = cleaned_lines
|
|
148
|
+
result = []
|
|
149
|
+
current_context = []
|
|
150
|
+
|
|
151
|
+
lines.each do |line|
|
|
152
|
+
stripped = line.strip
|
|
153
|
+
|
|
154
|
+
# Track class/module context
|
|
155
|
+
if stripped.match?(/^class\s+(\w+)/)
|
|
156
|
+
match = stripped.match(/^class\s+(\w+)/)
|
|
157
|
+
class_name = match[1]
|
|
158
|
+
current_context << class_name
|
|
159
|
+
|
|
160
|
+
# Insert class annotations before class definition
|
|
161
|
+
if anns = konpeito_annotations[class_name]
|
|
162
|
+
anns.each { |ann| result << "#{ann}\n" }
|
|
163
|
+
end
|
|
164
|
+
elsif stripped.match?(/^module\s+(\w+)/)
|
|
165
|
+
match = stripped.match(/^module\s+(\w+)/)
|
|
166
|
+
module_name = match[1]
|
|
167
|
+
current_context << module_name
|
|
168
|
+
|
|
169
|
+
# Insert module annotations before module definition
|
|
170
|
+
if anns = konpeito_annotations[module_name]
|
|
171
|
+
anns.each { |ann| result << "#{ann}\n" }
|
|
172
|
+
end
|
|
173
|
+
elsif stripped == "end"
|
|
174
|
+
current_context.pop
|
|
175
|
+
elsif stripped.match?(/^def\s+(self\.)?(\w+[?!=]?):/)
|
|
176
|
+
# Method definition in RBS
|
|
177
|
+
match = stripped.match(/^def\s+(self\.)?(\w+[?!=]?):/)
|
|
178
|
+
singleton = match[1] ? "." : "#"
|
|
179
|
+
method_name = match[2]
|
|
180
|
+
context = current_context.last
|
|
181
|
+
|
|
182
|
+
if context
|
|
183
|
+
key = "#{context}#{singleton}#{method_name}"
|
|
184
|
+
if anns = konpeito_annotations[key]
|
|
185
|
+
# Get the indentation from the current line
|
|
186
|
+
indent = line[/^\s*/]
|
|
187
|
+
anns.each { |ann| result << "#{indent}#{ann}\n" }
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
result << line
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
result.join
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# KonpeitoCompression - Data compression using zlib
|
|
2
|
+
#
|
|
3
|
+
# This module provides compression and decompression using the zlib library.
|
|
4
|
+
# It is implemented as a C extension for maximum performance.
|
|
5
|
+
#
|
|
6
|
+
# Usage:
|
|
7
|
+
# require 'konpeito/stdlib/compression'
|
|
8
|
+
#
|
|
9
|
+
# # Gzip format (most common for HTTP, file archives)
|
|
10
|
+
# compressed = KonpeitoCompression.gzip("Hello, World!")
|
|
11
|
+
# original = KonpeitoCompression.gunzip(compressed)
|
|
12
|
+
#
|
|
13
|
+
# # With compression level
|
|
14
|
+
# fast = KonpeitoCompression.deflate(data, KonpeitoCompression::BEST_SPEED)
|
|
15
|
+
# small = KonpeitoCompression.deflate(data, KonpeitoCompression::BEST_COMPRESSION)
|
|
16
|
+
#
|
|
17
|
+
# # Raw deflate (for custom protocols, no header overhead)
|
|
18
|
+
# compressed = KonpeitoCompression.deflate("Hello", nil)
|
|
19
|
+
# original = KonpeitoCompression.inflate(compressed)
|
|
20
|
+
#
|
|
21
|
+
# # Zlib format (includes checksum, good for data integrity)
|
|
22
|
+
# compressed = KonpeitoCompression.zlib_compress("Hello")
|
|
23
|
+
# original = KonpeitoCompression.zlib_decompress(compressed, nil)
|
|
24
|
+
|
|
25
|
+
# Try to load the native extension
|
|
26
|
+
begin
|
|
27
|
+
require_relative 'konpeito_compression'
|
|
28
|
+
rescue LoadError => e
|
|
29
|
+
# Fallback to Zlib module if native extension is not available
|
|
30
|
+
require 'zlib'
|
|
31
|
+
|
|
32
|
+
module KonpeitoCompression
|
|
33
|
+
BEST_SPEED = Zlib::BEST_SPEED
|
|
34
|
+
BEST_COMPRESSION = Zlib::BEST_COMPRESSION
|
|
35
|
+
DEFAULT_COMPRESSION = Zlib::DEFAULT_COMPRESSION
|
|
36
|
+
|
|
37
|
+
class << self
|
|
38
|
+
def gzip(data)
|
|
39
|
+
Zlib.gzip(data)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def gunzip(data)
|
|
43
|
+
Zlib.gunzip(data)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def deflate(data, level = nil)
|
|
47
|
+
level ||= Zlib::DEFAULT_COMPRESSION
|
|
48
|
+
deflater = Zlib::Deflate.new(level, -Zlib::MAX_WBITS)
|
|
49
|
+
result = deflater.deflate(data, Zlib::FINISH)
|
|
50
|
+
deflater.close
|
|
51
|
+
result
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def inflate(data)
|
|
55
|
+
inflater = Zlib::Inflate.new(-Zlib::MAX_WBITS)
|
|
56
|
+
result = inflater.inflate(data)
|
|
57
|
+
inflater.close
|
|
58
|
+
result
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def zlib_compress(data)
|
|
62
|
+
Zlib.deflate(data)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def zlib_decompress(data, max_size = nil)
|
|
66
|
+
Zlib.inflate(data)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
warn "KonpeitoCompression: Native extension not available, using Zlib fallback (#{e.message})"
|
|
72
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# KonpeitoCompression - Data compression using zlib
|
|
2
|
+
#
|
|
3
|
+
# Usage:
|
|
4
|
+
# # Gzip format (common for HTTP compression, file archives)
|
|
5
|
+
# compressed = KonpeitoCompression.gzip("Hello, World!")
|
|
6
|
+
# original = KonpeitoCompression.gunzip(compressed)
|
|
7
|
+
#
|
|
8
|
+
# # Raw deflate (no header, for custom protocols)
|
|
9
|
+
# compressed = KonpeitoCompression.deflate("Hello", nil)
|
|
10
|
+
# original = KonpeitoCompression.inflate(compressed)
|
|
11
|
+
#
|
|
12
|
+
# # Zlib format (with checksum header)
|
|
13
|
+
# compressed = KonpeitoCompression.zlib_compress("Hello")
|
|
14
|
+
# original = KonpeitoCompression.zlib_decompress(compressed, nil)
|
|
15
|
+
|
|
16
|
+
module KonpeitoCompression
|
|
17
|
+
# Compress data using gzip format (RFC 1952)
|
|
18
|
+
# @param data [String] Data to compress
|
|
19
|
+
# @return [String] Gzip-compressed data (binary string)
|
|
20
|
+
# @raise [RuntimeError] if compression fails
|
|
21
|
+
def self.gzip: (String data) -> String
|
|
22
|
+
|
|
23
|
+
# Decompress gzip data (RFC 1952)
|
|
24
|
+
# Also accepts zlib format (auto-detected)
|
|
25
|
+
# @param data [String] Gzip-compressed data
|
|
26
|
+
# @return [String] Decompressed data
|
|
27
|
+
# @raise [RuntimeError] if decompression fails
|
|
28
|
+
def self.gunzip: (String data) -> String
|
|
29
|
+
|
|
30
|
+
# Compress data using raw deflate (RFC 1951, no header)
|
|
31
|
+
# @param data [String] Data to compress
|
|
32
|
+
# @param level [Integer?] Compression level (0-9, nil for default)
|
|
33
|
+
# @return [String] Deflate-compressed data (binary string)
|
|
34
|
+
# @raise [RuntimeError] if compression fails
|
|
35
|
+
def self.deflate: (String data, Integer? level) -> String
|
|
36
|
+
|
|
37
|
+
# Decompress raw deflate data (RFC 1951, no header)
|
|
38
|
+
# @param data [String] Deflate-compressed data
|
|
39
|
+
# @return [String] Decompressed data
|
|
40
|
+
# @raise [RuntimeError] if decompression fails
|
|
41
|
+
def self.inflate: (String data) -> String
|
|
42
|
+
|
|
43
|
+
# Compress data using zlib format (RFC 1950, with header)
|
|
44
|
+
# @param data [String] Data to compress
|
|
45
|
+
# @return [String] Zlib-compressed data (binary string)
|
|
46
|
+
# @raise [RuntimeError] if compression fails
|
|
47
|
+
def self.zlib_compress: (String data) -> String
|
|
48
|
+
|
|
49
|
+
# Decompress zlib data (RFC 1950, with header)
|
|
50
|
+
# @param data [String] Zlib-compressed data
|
|
51
|
+
# @param max_size [Integer?] Maximum decompressed size (nil for 100MB default)
|
|
52
|
+
# @return [String] Decompressed data
|
|
53
|
+
# @raise [RuntimeError] if decompression fails or exceeds max_size
|
|
54
|
+
def self.zlib_decompress: (String data, Integer? max_size) -> String
|
|
55
|
+
|
|
56
|
+
# Compression level constants
|
|
57
|
+
BEST_SPEED: Integer # Fastest compression (level 1)
|
|
58
|
+
BEST_COMPRESSION: Integer # Best compression ratio (level 9)
|
|
59
|
+
DEFAULT_COMPRESSION: Integer # Default compression (level 6)
|
|
60
|
+
end
|