brotli 0.2.3 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (92) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/main.yml +34 -0
  3. data/.github/workflows/publish.yml +34 -0
  4. data/Gemfile +6 -3
  5. data/Rakefile +16 -9
  6. data/brotli.gemspec +7 -13
  7. data/ext/brotli/brotli.c +209 -31
  8. data/ext/brotli/buffer.c +1 -7
  9. data/ext/brotli/buffer.h +1 -1
  10. data/ext/brotli/extconf.rb +20 -18
  11. data/lib/brotli/version.rb +1 -1
  12. data/test/brotli_test.rb +104 -0
  13. data/test/brotli_writer_test.rb +36 -0
  14. data/test/test_helper.rb +8 -0
  15. data/vendor/brotli/c/common/constants.c +15 -0
  16. data/vendor/brotli/c/common/constants.h +136 -0
  17. data/vendor/brotli/c/common/context.c +156 -0
  18. data/vendor/brotli/c/common/context.h +4 -152
  19. data/vendor/brotli/c/common/dictionary.bin.br +0 -0
  20. data/vendor/brotli/c/common/dictionary.c +10 -1
  21. data/vendor/brotli/c/common/platform.c +22 -0
  22. data/vendor/brotli/c/common/platform.h +43 -17
  23. data/vendor/brotli/c/common/transform.c +59 -3
  24. data/vendor/brotli/c/common/transform.h +5 -0
  25. data/vendor/brotli/c/common/version.h +2 -2
  26. data/vendor/brotli/c/dec/bit_reader.c +28 -0
  27. data/vendor/brotli/c/dec/bit_reader.h +58 -16
  28. data/vendor/brotli/c/dec/decode.c +353 -251
  29. data/vendor/brotli/c/dec/huffman.h +6 -12
  30. data/vendor/brotli/c/dec/prefix.h +0 -18
  31. data/vendor/brotli/c/dec/state.c +9 -14
  32. data/vendor/brotli/c/dec/state.h +144 -37
  33. data/vendor/brotli/c/enc/backward_references.c +8 -7
  34. data/vendor/brotli/c/enc/backward_references.h +5 -4
  35. data/vendor/brotli/c/enc/backward_references_hq.c +51 -33
  36. data/vendor/brotli/c/enc/backward_references_hq.h +11 -8
  37. data/vendor/brotli/c/enc/backward_references_inc.h +24 -14
  38. data/vendor/brotli/c/enc/block_splitter.c +3 -3
  39. data/vendor/brotli/c/enc/block_splitter_inc.h +15 -6
  40. data/vendor/brotli/c/enc/brotli_bit_stream.c +13 -30
  41. data/vendor/brotli/c/enc/cluster_inc.h +6 -3
  42. data/vendor/brotli/c/enc/command.c +28 -0
  43. data/vendor/brotli/c/enc/command.h +12 -12
  44. data/vendor/brotli/c/enc/compress_fragment_two_pass.c +1 -1
  45. data/vendor/brotli/c/enc/dictionary_hash.c +1826 -1100
  46. data/vendor/brotli/c/enc/dictionary_hash.h +2 -1
  47. data/vendor/brotli/c/enc/encode.c +104 -39
  48. data/vendor/brotli/c/enc/encoder_dict.c +3 -2
  49. data/vendor/brotli/c/enc/encoder_dict.h +3 -1
  50. data/vendor/brotli/c/enc/entropy_encode.c +2 -0
  51. data/vendor/brotli/c/enc/entropy_encode.h +2 -2
  52. data/vendor/brotli/c/enc/fast_log.c +105 -0
  53. data/vendor/brotli/c/enc/fast_log.h +19 -100
  54. data/vendor/brotli/c/enc/find_match_length.h +2 -3
  55. data/vendor/brotli/c/enc/hash.h +80 -90
  56. data/vendor/brotli/c/enc/hash_composite_inc.h +52 -63
  57. data/vendor/brotli/c/enc/hash_forgetful_chain_inc.h +88 -49
  58. data/vendor/brotli/c/enc/hash_longest_match64_inc.h +50 -50
  59. data/vendor/brotli/c/enc/hash_longest_match_inc.h +53 -50
  60. data/vendor/brotli/c/enc/hash_longest_match_quickly_inc.h +91 -60
  61. data/vendor/brotli/c/enc/hash_rolling_inc.h +23 -27
  62. data/vendor/brotli/c/enc/hash_to_binary_tree_inc.h +39 -38
  63. data/vendor/brotli/c/enc/memory.h +24 -12
  64. data/vendor/brotli/c/enc/metablock.c +23 -27
  65. data/vendor/brotli/c/enc/metablock_inc.h +1 -1
  66. data/vendor/brotli/c/enc/params.h +3 -1
  67. data/vendor/brotli/c/enc/ringbuffer.h +4 -1
  68. data/vendor/brotli/c/enc/utf8_util.c +1 -1
  69. data/vendor/brotli/c/enc/write_bits.h +27 -25
  70. data/vendor/brotli/c/include/brotli/encode.h +22 -1
  71. data/vendor/brotli/c/include/brotli/port.h +14 -0
  72. metadata +17 -97
  73. data/.travis.yml +0 -31
  74. data/docs/Brotli.html +0 -485
  75. data/docs/Brotli/Error.html +0 -124
  76. data/docs/_index.html +0 -122
  77. data/docs/class_list.html +0 -51
  78. data/docs/css/common.css +0 -1
  79. data/docs/css/full_list.css +0 -58
  80. data/docs/css/style.css +0 -496
  81. data/docs/file.README.html +0 -127
  82. data/docs/file_list.html +0 -56
  83. data/docs/frames.html +0 -17
  84. data/docs/index.html +0 -127
  85. data/docs/js/app.js +0 -292
  86. data/docs/js/full_list.js +0 -216
  87. data/docs/js/jquery.js +0 -4
  88. data/docs/method_list.html +0 -67
  89. data/docs/top-level-namespace.html +0 -110
  90. data/spec/brotli_spec.rb +0 -88
  91. data/spec/inflate_spec.rb +0 -75
  92. data/spec/spec_helper.rb +0 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ab7474a5a27fb0167098bc9838f8e57bc78082d596c5e38a7c86764fdf62bf13
4
- data.tar.gz: 5a0b4d731bfd0fdbdd19a2cec36973cfc04460237acf58ac03dda51e8da82fe1
3
+ metadata.gz: 410f0b599c6bf42f90cb7fa83c6710304ad0fb018b1f4b5560bfadadaef165d9
4
+ data.tar.gz: 03fbcca525c9705b99935ab2ea4db0bb80e4c6a960d3010450a173c5b305eb43
5
5
  SHA512:
6
- metadata.gz: ae940a4cb85d44b0ad84a01fde9e8aaf285366dfcbccca4ba68619966005e1f003046de298b5d69098a4d3fcfd2a020ef49fa6eb5a3a0c790f59cd3060138bb6
7
- data.tar.gz: 92b9e926ad5b98f4afc7522c0b7a1a7490f32ed474d0881643f09ae8747ada70f25aa77360dc4707c369c6e58bfa747fc0eca7efb8cc05ee2f752e802202b017
6
+ metadata.gz: fe26f6b7a9a2f3a0bf0ab5d1e79ff89ff8dc2a763e3b8beb073feb365f6ae222dcf277672bbbe2ac7aeaa71f2b024edd6ce49a6a7254452897fdbfef61f422a5
7
+ data.tar.gz: c1952c3b820fa2ec0b5a1e1567acfe831fcc1a6131f07e12acf3b26595c3bda90c89182abfcc57730febe5311906632ea8c19a21e16e866a5e620a8b85cfa2d4
@@ -0,0 +1,34 @@
1
+ name: Ruby
2
+
3
+ on: [pull_request]
4
+
5
+ jobs:
6
+ build:
7
+ strategy:
8
+ fail-fast: false
9
+ matrix:
10
+ ruby: [2.5, 2.6, 2.7, 3.0]
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - uses: actions/checkout@v2
14
+ with:
15
+ submodules: true
16
+ - name: Set up Ruby
17
+ uses: ruby/setup-ruby@v1
18
+ with:
19
+ ruby-version: ${{ matrix.ruby }}
20
+ bundler-cache: true
21
+ - name: Run the default task
22
+ run: |
23
+ bundle exec rake clobber test build
24
+ gem install --no-document "$(ls pkg/brotli-*.gem)"
25
+ cat <<EOF | ruby
26
+ require "brotli"
27
+ if Brotli.inflate(Brotli.deflate(File.read("README.md"))) == File.read("README.md")
28
+ puts "OK"
29
+ exit 0
30
+ else
31
+ puts "NG"
32
+ exit 0
33
+ end
34
+ EOF
@@ -0,0 +1,34 @@
1
+ name: Publish Gem
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - 'v*'
7
+
8
+ jobs:
9
+ build:
10
+ strategy:
11
+ fail-fast: false
12
+ matrix:
13
+ ruby: [2.7]
14
+ runs-on: ubuntu-latest
15
+ steps:
16
+ - uses: actions/checkout@v2
17
+ with:
18
+ submodules: true
19
+ - name: Set up Ruby
20
+ uses: ruby/setup-ruby@v1
21
+ with:
22
+ ruby-version: ${{ matrix.ruby }}
23
+ bundler-cache: true
24
+ - name: Run release task
25
+ run: |
26
+ mkdir -p ~/.gem
27
+ cat << EOF > ~/.gem/credentials
28
+ ---
29
+ :github: Bearer ${{secrets.GITHUB_TOKEN}}
30
+ :rubygems_api_key: ${{secrets.RUBYGEMS_API_KEY}}
31
+ EOF
32
+ chmod 600 ~/.gem/credentials
33
+ bundle exec rake release[remote]
34
+ rm -f ~/.gem/credentials
data/Gemfile CHANGED
@@ -1,7 +1,10 @@
1
- source 'https://rubygems.org'
1
+ source "https://rubygems.org"
2
2
 
3
3
  # Specify your gem's dependencies in brotli.gemspec
4
4
  gemspec
5
5
 
6
- gem 'travis'
7
- gem 'yard'
6
+ gem "rake", "~> 13.0"
7
+ gem "rake-compiler"
8
+ gem "test-unit", "~> 3.0"
9
+ gem "test-unit-rr"
10
+ gem "rantly"
data/Rakefile CHANGED
@@ -1,18 +1,25 @@
1
+ require "bundler/setup"
1
2
  require "bundler/gem_tasks"
2
- require "rspec/core/rake_task"
3
+ require "rake/clean"
4
+ require "rake/testtask"
3
5
  require "rake/extensiontask"
4
- require "yard"
5
6
 
6
- RSpec::Core::RakeTask.new(:spec)
7
+ CLEAN.include("ext/brotli/common")
8
+ CLEAN.include("ext/brotli/dec")
9
+ CLEAN.include("ext/brotli/enc")
10
+ CLEAN.include("ext/brotli/include")
7
11
 
8
- task :default => [:compile, :spec]
9
-
10
- task :build => :compile
12
+ Rake::TestTask.new(:test) do |t|
13
+ t.libs << "test"
14
+ t.test_files = FileList["test/**/*_test.rb"]
15
+ t.warning = true
16
+ t.verbose = true
17
+ end
11
18
 
12
19
  Rake::ExtensionTask.new("brotli") do |ext|
13
20
  ext.lib_dir = "lib/brotli"
14
21
  end
15
22
 
16
- YARD::Rake::YardocTask.new do |t|
17
- t.options = ["--no-progress", "--output-dir", "docs"]
18
- end
23
+ task :build => :compile
24
+ task :test => :compile
25
+ task :default => :test
@@ -1,7 +1,7 @@
1
1
  # coding: utf-8
2
2
  lib = File.expand_path('../lib', __FILE__)
3
3
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require 'brotli/version'
4
+ require "brotli/version"
5
5
 
6
6
  Gem::Specification.new do |spec|
7
7
  spec.name = "brotli"
@@ -9,25 +9,19 @@ Gem::Specification.new do |spec|
9
9
  spec.authors = ["miyucy"]
10
10
  spec.email = ["fistfvck@gmail.com"]
11
11
 
12
- spec.summary = %q{Brotli compressor/decompressor}
13
- spec.description = %q{Brotli compressor/decompressor}
12
+ spec.summary = "Brotli compressor/decompressor"
13
+ spec.description = "Brotli compressor/decompressor"
14
14
  spec.homepage = "https://github.com/miyucy/brotli"
15
15
  spec.license = "MIT"
16
16
 
17
- spec.test_files = `git ls-files -z -- spec`.split("\x0")
17
+ spec.test_files = `git ls-files -z -- test`.split("\x0")
18
18
  spec.files = `git ls-files -z`.split("\x0")
19
19
  spec.files -= spec.test_files
20
- spec.files -= ['vendor/brotli']
21
- spec.files += Dir['vendor/brotli/c/{common,enc,dec,include}/**/*']
22
- spec.files += ['vendor/brotli/LICENSE']
20
+ spec.files -= ["vendor/brotli"]
21
+ spec.files += Dir["vendor/brotli/c/{common,enc,dec,include}/**/*"]
22
+ spec.files += ["vendor/brotli/LICENSE"]
23
23
  spec.bindir = "exe"
24
24
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
25
25
  spec.require_paths = ["lib"]
26
26
  spec.extensions = ["ext/brotli/extconf.rb"]
27
-
28
- spec.add_development_dependency "bundler"
29
- spec.add_development_dependency "rake"
30
- spec.add_development_dependency "rake-compiler"
31
- spec.add_development_dependency "rspec"
32
- spec.add_development_dependency "rantly"
33
27
  end
@@ -2,20 +2,19 @@
2
2
 
3
3
  #define CSTR2SYM(x) ID2SYM(rb_intern(x))
4
4
 
5
- static VALUE rb_mBrotli;
6
5
  static VALUE rb_eBrotli;
7
6
 
8
- static void*
7
+ static inline void*
9
8
  brotli_alloc(void* opaque, size_t size)
10
9
  {
11
- return malloc(size);
10
+ return ruby_xmalloc(size);
12
11
  }
13
12
 
14
- static void
13
+ static inline void
15
14
  brotli_free(void* opaque, void* address)
16
15
  {
17
16
  if (address) {
18
- free(address);
17
+ ruby_xfree(address);
19
18
  }
20
19
  }
21
20
 
@@ -138,11 +137,10 @@ brotli_deflate_set_mode(BrotliEncoderState* s, VALUE value)
138
137
  static void
139
138
  brotli_deflate_set_quality(BrotliEncoderState* s, VALUE value)
140
139
  {
141
- uint32_t param;
142
140
  if (NIL_P(value)) {
143
141
  return;
144
142
  } else {
145
- param = NUM2INT(value);
143
+ int32_t param = NUM2INT(value);
146
144
  if (0 <= param && param <= 11) {
147
145
  BrotliEncoderSetParameter(s, BROTLI_PARAM_QUALITY, param);
148
146
  } else {
@@ -154,11 +152,10 @@ brotli_deflate_set_quality(BrotliEncoderState* s, VALUE value)
154
152
  static void
155
153
  brotli_deflate_set_lgwin(BrotliEncoderState* s, VALUE value)
156
154
  {
157
- uint32_t param;
158
155
  if (NIL_P(value)) {
159
156
  return;
160
157
  } else {
161
- param = NUM2INT(value);
158
+ int32_t param = NUM2INT(value);
162
159
  if (10 <= param && param <= 24) {
163
160
  BrotliEncoderSetParameter(s, BROTLI_PARAM_LGWIN, param);
164
161
  } else {
@@ -170,11 +167,10 @@ brotli_deflate_set_lgwin(BrotliEncoderState* s, VALUE value)
170
167
  static void
171
168
  brotli_deflate_set_lgblock(BrotliEncoderState* s, VALUE value)
172
169
  {
173
- uint32_t param;
174
170
  if (NIL_P(value)) {
175
171
  return;
176
172
  } else {
177
- param = NUM2INT(value);
173
+ int32_t param = NUM2INT(value);
178
174
  if ((param == 0) || (16 <= param && param <= 24)) {
179
175
  BrotliEncoderSetParameter(s, BROTLI_PARAM_LGBLOCK, param);
180
176
  } else {
@@ -241,26 +237,6 @@ brotli_deflate_no_gvl(void *arg)
241
237
  return arg;
242
238
  }
243
239
 
244
- /*
245
- * call-seq:
246
- * Brotli.deflate(str, opts=nil) -> String
247
- * @param [String] str
248
- * string
249
- * @param [Hash] opts
250
- * options
251
- * @option opts [Symbol] :mode
252
- * Deflate mode
253
- * * :generic
254
- * * :text
255
- * * :font
256
- * @option opts [Integer] :quality
257
- * quality 0-11
258
- * @option opts [Integer] :lgwin
259
- * lgwin 10-24
260
- * @option opts [Integer] :lgblock
261
- * lgblock 16-24 or 0
262
- * @return [String] Deflated string
263
- */
264
240
  static VALUE
265
241
  brotli_deflate(int argc, VALUE *argv, VALUE self)
266
242
  {
@@ -268,6 +244,10 @@ brotli_deflate(int argc, VALUE *argv, VALUE self)
268
244
  brotli_deflate_args_t args;
269
245
 
270
246
  rb_scan_args(argc, argv, "11", &str, &opts);
247
+ if (NIL_P(str)) {
248
+ rb_raise(rb_eArgError, "input should not be nil");
249
+ return Qnil;
250
+ }
271
251
  StringValue(str);
272
252
 
273
253
  args.str = (uint8_t*)RSTRING_PTR(str);
@@ -293,6 +273,185 @@ brotli_deflate(int argc, VALUE *argv, VALUE self)
293
273
  return value;
294
274
  }
295
275
 
276
+ /*******************************************************************************
277
+ * version
278
+ ******************************************************************************/
279
+
280
+ static VALUE brotli_version(VALUE klass) {
281
+ uint32_t ver = BrotliEncoderVersion();
282
+ char version[255];
283
+ snprintf(version, sizeof(version), "%u.%u.%u", ver >> 24, (ver >> 12) & 0xFFF, ver & 0xFFF);
284
+ return rb_str_new2(version);
285
+ }
286
+
287
+ /*******************************************************************************
288
+ * Writer
289
+ ******************************************************************************/
290
+
291
+ static ID id_write, id_flush, id_close;
292
+
293
+ struct brotli {
294
+ VALUE io;
295
+ BrotliEncoderState* state;
296
+ };
297
+
298
+ static void br_mark(void *p)
299
+ {
300
+ struct brotli *br = p;
301
+ rb_gc_mark(br->io);
302
+ }
303
+
304
+ static void br_free(void *p)
305
+ {
306
+ struct brotli* br = p;
307
+ BrotliEncoderDestroyInstance(br->state);
308
+ br->state = NULL;
309
+ br->io = Qnil;
310
+ ruby_xfree(br);
311
+ }
312
+
313
+ static size_t br_memsize(const void *p)
314
+ {
315
+ return sizeof(struct brotli);
316
+ }
317
+
318
+ static const rb_data_type_t brotli_data_type = {
319
+ "brotli",
320
+ { br_mark, br_free, br_memsize },
321
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
322
+ };
323
+
324
+ typedef struct {
325
+ BrotliEncoderState* state;
326
+ BrotliEncoderOperation op;
327
+ size_t available_in;
328
+ const uint8_t* next_in;
329
+ } brotli_encoder_args_t;
330
+
331
+ static void* compress_no_gvl(void *ptr) {
332
+ brotli_encoder_args_t *args = ptr;
333
+ size_t zero = 0;
334
+ if (!BrotliEncoderCompressStream(args->state, args->op,
335
+ &args->available_in, &args->next_in,
336
+ &zero, NULL, NULL)) {
337
+ rb_raise(rb_eBrotli, "BrotliEncoderCompressStream failed");
338
+ }
339
+ return NULL;
340
+ }
341
+
342
+ static size_t push_output(struct brotli *br) {
343
+ size_t len = 0;
344
+ if (BrotliEncoderHasMoreOutput(br->state)) {
345
+ const uint8_t* out = BrotliEncoderTakeOutput(br->state, &len);
346
+ if (len > 0) {
347
+ rb_funcall(br->io, id_write, 1, rb_str_new((const char*)out, len));
348
+ }
349
+ }
350
+ return len;
351
+ }
352
+
353
+ static VALUE rb_writer_alloc(VALUE klass) {
354
+ struct brotli *br;
355
+ VALUE obj = TypedData_Make_Struct(klass, struct brotli, &brotli_data_type, br);
356
+ br->io = Qnil;
357
+ br->state = BrotliEncoderCreateInstance(brotli_alloc, brotli_free, NULL);
358
+ if (!br->state) {
359
+ rb_raise(rb_eNoMemError, "BrotliEncoderCreateInstance failed");
360
+ return Qnil;
361
+ }
362
+ return obj;
363
+ }
364
+
365
+ static VALUE rb_writer_initialize(int argc, VALUE* argv, VALUE self) {
366
+ VALUE io = Qnil;
367
+ VALUE opts = Qnil;
368
+ rb_scan_args(argc, argv, "11", &io, &opts);
369
+ if (NIL_P(io)) {
370
+ rb_raise(rb_eArgError, "io should not be nil");
371
+ return Qnil;
372
+ }
373
+
374
+ struct brotli *br;
375
+ TypedData_Get_Struct(self, struct brotli, &brotli_data_type, br);
376
+ brotli_deflate_parse_options(br->state, opts);
377
+ br->io = io;
378
+ return self;
379
+ }
380
+
381
+ static VALUE rb_writer_write(VALUE self, VALUE buf) {
382
+ struct brotli* br;
383
+ TypedData_Get_Struct(self, struct brotli, &brotli_data_type, br);
384
+ StringValue(buf);
385
+
386
+ const size_t total = (size_t)RSTRING_LEN(buf);
387
+
388
+ brotli_encoder_args_t args = {
389
+ .state = br->state,
390
+ .op = BROTLI_OPERATION_PROCESS,
391
+ .available_in = total,
392
+ .next_in = (uint8_t*)RSTRING_PTR(buf)
393
+ };
394
+
395
+ while (args.available_in > 0) {
396
+ rb_thread_call_without_gvl(compress_no_gvl, (void*)&args, NULL, NULL);
397
+ push_output(br);
398
+ }
399
+
400
+ return SIZET2NUM(total);
401
+ }
402
+
403
+ static VALUE rb_writer_finish(VALUE self) {
404
+ struct brotli* br;
405
+ TypedData_Get_Struct(self, struct brotli, &brotli_data_type, br);
406
+
407
+ brotli_encoder_args_t args = {
408
+ .state = br->state,
409
+ .op = BROTLI_OPERATION_FINISH,
410
+ .available_in = 0,
411
+ .next_in = NULL
412
+ };
413
+
414
+ while (!BrotliEncoderIsFinished(br->state)) {
415
+ rb_thread_call_without_gvl(compress_no_gvl, (void*)&args, NULL, NULL);
416
+ push_output(br);
417
+ }
418
+ return br->io;
419
+ }
420
+
421
+ static VALUE rb_writer_flush(VALUE self) {
422
+ struct brotli *br;
423
+ TypedData_Get_Struct(self, struct brotli, &brotli_data_type, br);
424
+
425
+ brotli_encoder_args_t args = {
426
+ .state = br->state,
427
+ .op = BROTLI_OPERATION_FLUSH,
428
+ .available_in = 0,
429
+ .next_in = NULL
430
+ };
431
+
432
+ do {
433
+ rb_thread_call_without_gvl(compress_no_gvl, (void*)&args, NULL, NULL);
434
+ push_output(br);
435
+ } while (BrotliEncoderHasMoreOutput(br->state));
436
+
437
+ if (rb_respond_to(br->io, id_flush)) {
438
+ rb_funcall(br->io, id_flush, 0);
439
+ }
440
+ return self;
441
+ }
442
+
443
+ static VALUE rb_writer_close(VALUE self) {
444
+ struct brotli* br;
445
+ TypedData_Get_Struct(self, struct brotli, &brotli_data_type, br);
446
+
447
+ rb_writer_finish(self);
448
+
449
+ if (rb_respond_to(br->io, id_close)) {
450
+ rb_funcall(br->io, id_close, 0);
451
+ }
452
+ return br->io;
453
+ }
454
+
296
455
  /*******************************************************************************
297
456
  * entry
298
457
  ******************************************************************************/
@@ -300,8 +459,27 @@ brotli_deflate(int argc, VALUE *argv, VALUE self)
300
459
  void
301
460
  Init_brotli(void)
302
461
  {
462
+ #if HAVE_RB_EXT_RACTOR_SAFE
463
+ rb_ext_ractor_safe(true);
464
+ #endif
465
+
466
+ VALUE rb_mBrotli;
467
+ VALUE rb_Writer;
303
468
  rb_mBrotli = rb_define_module("Brotli");
304
469
  rb_eBrotli = rb_define_class_under(rb_mBrotli, "Error", rb_eStandardError);
470
+ rb_global_variable(&rb_eBrotli);
305
471
  rb_define_singleton_method(rb_mBrotli, "deflate", RUBY_METHOD_FUNC(brotli_deflate), -1);
306
472
  rb_define_singleton_method(rb_mBrotli, "inflate", RUBY_METHOD_FUNC(brotli_inflate), 1);
473
+ rb_define_singleton_method(rb_mBrotli, "version", RUBY_METHOD_FUNC(brotli_version), 0);
474
+ // Brotli::Writer
475
+ id_write = rb_intern("write");
476
+ id_flush = rb_intern("flush");
477
+ id_close = rb_intern("close");
478
+ rb_Writer = rb_define_class_under(rb_mBrotli, "Writer", rb_cObject);
479
+ rb_define_alloc_func(rb_Writer, rb_writer_alloc);
480
+ rb_define_method(rb_Writer, "initialize", RUBY_METHOD_FUNC(rb_writer_initialize), -1);
481
+ rb_define_method(rb_Writer, "write", RUBY_METHOD_FUNC(rb_writer_write), 1);
482
+ rb_define_method(rb_Writer, "finish", RUBY_METHOD_FUNC(rb_writer_finish), 0);
483
+ rb_define_method(rb_Writer, "flush", RUBY_METHOD_FUNC(rb_writer_flush), 0);
484
+ rb_define_method(rb_Writer, "close", RUBY_METHOD_FUNC(rb_writer_close), 0);
307
485
  }