ruby-brs 1.1.1 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,7 +2,6 @@
2
2
  // Copyright (c) 2019 AUTHORS, MIT License.
3
3
 
4
4
  #include "brs_ext/buffer.h"
5
- #include "brs_ext/common.h"
6
5
  #include "brs_ext/io.h"
7
6
  #include "brs_ext/option.h"
8
7
  #include "brs_ext/stream/compressor.h"
@@ -5,21 +5,18 @@
5
5
 
6
6
  #include <brotli/decode.h>
7
7
  #include <brotli/encode.h>
8
- #include <stdbool.h>
9
- #include <stdlib.h>
10
8
 
11
- #include "brs_ext/common.h"
12
9
  #include "brs_ext/error.h"
13
10
  #include "ruby.h"
14
11
 
15
12
  // -- values --
16
13
 
17
- static inline VALUE get_raw_option_value(VALUE options, const char* name)
14
+ static inline VALUE get_raw_value(VALUE options, const char* name)
18
15
  {
19
16
  return rb_funcall(options, rb_intern("[]"), 1, ID2SYM(rb_intern(name)));
20
17
  }
21
18
 
22
- static inline bool get_bool_option_value(VALUE raw_value)
19
+ static inline bool get_bool_value(VALUE raw_value)
23
20
  {
24
21
  int raw_type = TYPE(raw_value);
25
22
  if (raw_type != T_TRUE && raw_type != T_FALSE) {
@@ -29,35 +26,39 @@ static inline bool get_bool_option_value(VALUE raw_value)
29
26
  return raw_type == T_TRUE;
30
27
  }
31
28
 
32
- static inline unsigned int get_uint_option_value(VALUE raw_value)
29
+ static inline unsigned int get_uint_value(VALUE raw_value)
33
30
  {
34
31
  Check_Type(raw_value, T_FIXNUM);
35
32
 
36
33
  return NUM2UINT(raw_value);
37
34
  }
38
35
 
39
- static inline BrotliEncoderMode get_mode_option_value(VALUE raw_value)
36
+ static inline size_t get_size_value(VALUE raw_value)
37
+ {
38
+ Check_Type(raw_value, T_FIXNUM);
39
+
40
+ return NUM2SIZET(raw_value);
41
+ }
42
+
43
+ static inline BrotliEncoderMode get_mode_value(VALUE raw_value)
40
44
  {
41
45
  Check_Type(raw_value, T_SYMBOL);
42
46
 
43
47
  ID raw_id = SYM2ID(raw_value);
44
48
  if (raw_id == rb_intern("text")) {
45
49
  return BROTLI_MODE_TEXT;
46
- }
47
- else if (raw_id == rb_intern("font")) {
50
+ } else if (raw_id == rb_intern("font")) {
48
51
  return BROTLI_MODE_FONT;
49
- }
50
- else if (raw_id == rb_intern("generic")) {
52
+ } else if (raw_id == rb_intern("generic")) {
51
53
  return BROTLI_MODE_GENERIC;
52
- }
53
- else {
54
+ } else {
54
55
  brs_ext_raise_error(BRS_EXT_ERROR_VALIDATE_FAILED);
55
56
  }
56
57
  }
57
58
 
58
- void brs_ext_get_option(VALUE options, brs_ext_option_t* option, brs_ext_option_type_t type, const char* name)
59
+ void brs_ext_resolve_option(VALUE options, brs_ext_option_t* option, brs_ext_option_type_t type, const char* name)
59
60
  {
60
- VALUE raw_value = get_raw_option_value(options, name);
61
+ VALUE raw_value = get_raw_value(options, name);
61
62
 
62
63
  option->has_value = raw_value != Qnil;
63
64
  if (!option->has_value) {
@@ -68,13 +69,13 @@ void brs_ext_get_option(VALUE options, brs_ext_option_t* option, brs_ext_option_
68
69
 
69
70
  switch (type) {
70
71
  case BRS_EXT_OPTION_TYPE_BOOL:
71
- value = get_bool_option_value(raw_value) ? 1 : 0;
72
+ value = get_bool_value(raw_value) ? 1 : 0;
72
73
  break;
73
74
  case BRS_EXT_OPTION_TYPE_UINT:
74
- value = (brs_ext_option_value_t)get_uint_option_value(raw_value);
75
+ value = (brs_ext_option_value_t) get_uint_value(raw_value);
75
76
  break;
76
77
  case BRS_EXT_OPTION_TYPE_MODE:
77
- value = (brs_ext_option_value_t)get_mode_option_value(raw_value);
78
+ value = (brs_ext_option_value_t) get_mode_value(raw_value);
78
79
  break;
79
80
  default:
80
81
  brs_ext_raise_error(BRS_EXT_ERROR_UNEXPECTED);
@@ -83,13 +84,18 @@ void brs_ext_get_option(VALUE options, brs_ext_option_t* option, brs_ext_option_
83
84
  option->value = value;
84
85
  }
85
86
 
86
- size_t brs_ext_get_size_option_value(VALUE options, const char* name)
87
+ bool brs_ext_get_bool_option_value(VALUE options, const char* name)
87
88
  {
88
- VALUE raw_value = get_raw_option_value(options, name);
89
+ VALUE raw_value = get_raw_value(options, name);
89
90
 
90
- Check_Type(raw_value, T_FIXNUM);
91
+ return get_bool_value(raw_value);
92
+ }
91
93
 
92
- return NUM2SIZET(raw_value);
94
+ size_t brs_ext_get_size_option_value(VALUE options, const char* name)
95
+ {
96
+ VALUE raw_value = get_raw_value(options, name);
97
+
98
+ return get_size_value(raw_value);
93
99
  }
94
100
 
95
101
  // -- set params --
@@ -108,7 +114,8 @@ brs_ext_result_t brs_ext_set_compressor_options(BrotliEncoderState* state_ptr, b
108
114
  SET_ENCODER_PARAM(state_ptr, BROTLI_PARAM_QUALITY, options->quality);
109
115
  SET_ENCODER_PARAM(state_ptr, BROTLI_PARAM_LGWIN, options->lgwin);
110
116
  SET_ENCODER_PARAM(state_ptr, BROTLI_PARAM_LGBLOCK, options->lgblock);
111
- SET_ENCODER_PARAM(state_ptr, BROTLI_PARAM_DISABLE_LITERAL_CONTEXT_MODELING, options->disable_literal_context_modeling);
117
+ SET_ENCODER_PARAM(
118
+ state_ptr, BROTLI_PARAM_DISABLE_LITERAL_CONTEXT_MODELING, options->disable_literal_context_modeling);
112
119
  SET_ENCODER_PARAM(state_ptr, BROTLI_PARAM_SIZE_HINT, options->size_hint);
113
120
  SET_ENCODER_PARAM(state_ptr, BROTLI_PARAM_LARGE_WINDOW, options->large_window);
114
121
 
@@ -118,9 +125,12 @@ brs_ext_result_t brs_ext_set_compressor_options(BrotliEncoderState* state_ptr, b
118
125
  #define SET_DECODER_PARAM(state_ptr, param, option) \
119
126
  SET_OPTION_VALUE(BrotliDecoderSetParameter, state_ptr, param, option);
120
127
 
121
- brs_ext_result_t brs_ext_set_decompressor_options(BrotliDecoderState* state_ptr, brs_ext_decompressor_options_t* options)
128
+ brs_ext_result_t brs_ext_set_decompressor_options(
129
+ BrotliDecoderState* state_ptr,
130
+ brs_ext_decompressor_options_t* options)
122
131
  {
123
- SET_DECODER_PARAM(state_ptr, BROTLI_DECODER_PARAM_DISABLE_RING_BUFFER_REALLOCATION, options->disable_ring_buffer_reallocation);
132
+ SET_DECODER_PARAM(
133
+ state_ptr, BROTLI_DECODER_PARAM_DISABLE_RING_BUFFER_REALLOCATION, options->disable_ring_buffer_reallocation);
124
134
  SET_DECODER_PARAM(state_ptr, BROTLI_DECODER_PARAM_LARGE_WINDOW, options->large_window);
125
135
 
126
136
  return 0;
@@ -136,11 +146,8 @@ void brs_ext_option_exports(VALUE root_module)
136
146
  {
137
147
  VALUE module = rb_define_module_under(root_module, "Option");
138
148
 
139
- VALUE modes = rb_ary_new_from_args(
140
- 3,
141
- ID2SYM(rb_intern("text")),
142
- ID2SYM(rb_intern("font")),
143
- ID2SYM(rb_intern("generic")));
149
+ VALUE modes =
150
+ rb_ary_new_from_args(3, ID2SYM(rb_intern("text")), ID2SYM(rb_intern("font")), ID2SYM(rb_intern("generic")));
144
151
  rb_define_const(module, "MODES", modes);
145
152
  RB_GC_GUARD(modes);
146
153
 
@@ -7,7 +7,6 @@
7
7
  #include <brotli/decode.h>
8
8
  #include <brotli/encode.h>
9
9
  #include <stdbool.h>
10
- #include <stdint.h>
11
10
  #include <stdlib.h>
12
11
 
13
12
  #include "brs_ext/common.h"
@@ -16,21 +15,24 @@
16
15
  // Default option values depends on brotli library.
17
16
  // We will set only user defined values.
18
17
 
19
- enum {
18
+ enum
19
+ {
20
20
  BRS_EXT_OPTION_TYPE_BOOL = 1,
21
21
  BRS_EXT_OPTION_TYPE_UINT,
22
22
  BRS_EXT_OPTION_TYPE_MODE
23
23
  };
24
24
 
25
- typedef uint_fast8_t brs_ext_option_type_t;
26
- typedef uint32_t brs_ext_option_value_t;
25
+ typedef brs_ext_byte_fast_t brs_ext_option_type_t;
26
+ typedef uint32_t brs_ext_option_value_t;
27
27
 
28
- typedef struct {
28
+ typedef struct
29
+ {
29
30
  bool has_value;
30
31
  brs_ext_option_value_t value;
31
32
  } brs_ext_option_t;
32
33
 
33
- typedef struct {
34
+ typedef struct
35
+ {
34
36
  brs_ext_option_t mode;
35
37
  brs_ext_option_t quality;
36
38
  brs_ext_option_t lgwin;
@@ -40,40 +42,45 @@ typedef struct {
40
42
  brs_ext_option_t large_window;
41
43
  } brs_ext_compressor_options_t;
42
44
 
43
- typedef struct {
45
+ typedef struct
46
+ {
44
47
  brs_ext_option_t disable_ring_buffer_reallocation;
45
48
  brs_ext_option_t large_window;
46
49
  } brs_ext_decompressor_options_t;
47
50
 
48
- void brs_ext_get_option(VALUE options, brs_ext_option_t* option, brs_ext_option_type_t type, const char* name);
49
-
50
- #define BRS_EXT_GET_OPTION(options, target_options, type, name) \
51
- brs_ext_get_option(options, &target_options.name, type, #name);
52
-
53
- #define BRS_EXT_GET_COMPRESSOR_OPTIONS(options) \
54
- brs_ext_compressor_options_t compressor_options; \
55
- \
56
- BRS_EXT_GET_OPTION(options, compressor_options, BRS_EXT_OPTION_TYPE_MODE, mode); \
57
- BRS_EXT_GET_OPTION(options, compressor_options, BRS_EXT_OPTION_TYPE_UINT, quality); \
58
- BRS_EXT_GET_OPTION(options, compressor_options, BRS_EXT_OPTION_TYPE_UINT, lgwin); \
59
- BRS_EXT_GET_OPTION(options, compressor_options, BRS_EXT_OPTION_TYPE_UINT, lgblock); \
60
- BRS_EXT_GET_OPTION(options, compressor_options, BRS_EXT_OPTION_TYPE_BOOL, disable_literal_context_modeling); \
61
- BRS_EXT_GET_OPTION(options, compressor_options, BRS_EXT_OPTION_TYPE_UINT, size_hint); \
62
- BRS_EXT_GET_OPTION(options, compressor_options, BRS_EXT_OPTION_TYPE_BOOL, large_window);
63
-
64
- #define BRS_EXT_GET_DECOMPRESSOR_OPTIONS(options) \
65
- brs_ext_decompressor_options_t decompressor_options; \
66
- \
67
- BRS_EXT_GET_OPTION(options, decompressor_options, BRS_EXT_OPTION_TYPE_BOOL, disable_ring_buffer_reallocation); \
68
- BRS_EXT_GET_OPTION(options, decompressor_options, BRS_EXT_OPTION_TYPE_BOOL, large_window);
69
-
51
+ void brs_ext_resolve_option(VALUE options, brs_ext_option_t* option, brs_ext_option_type_t type, const char* name);
52
+
53
+ #define BRS_EXT_RESOLVE_OPTION(options, target_options, type, name) \
54
+ brs_ext_resolve_option(options, &target_options.name, type, #name);
55
+
56
+ #define BRS_EXT_GET_COMPRESSOR_OPTIONS(options) \
57
+ brs_ext_compressor_options_t compressor_options; \
58
+ \
59
+ BRS_EXT_RESOLVE_OPTION(options, compressor_options, BRS_EXT_OPTION_TYPE_MODE, mode); \
60
+ BRS_EXT_RESOLVE_OPTION(options, compressor_options, BRS_EXT_OPTION_TYPE_UINT, quality); \
61
+ BRS_EXT_RESOLVE_OPTION(options, compressor_options, BRS_EXT_OPTION_TYPE_UINT, lgwin); \
62
+ BRS_EXT_RESOLVE_OPTION(options, compressor_options, BRS_EXT_OPTION_TYPE_UINT, lgblock); \
63
+ BRS_EXT_RESOLVE_OPTION(options, compressor_options, BRS_EXT_OPTION_TYPE_BOOL, disable_literal_context_modeling); \
64
+ BRS_EXT_RESOLVE_OPTION(options, compressor_options, BRS_EXT_OPTION_TYPE_UINT, size_hint); \
65
+ BRS_EXT_RESOLVE_OPTION(options, compressor_options, BRS_EXT_OPTION_TYPE_BOOL, large_window);
66
+
67
+ #define BRS_EXT_GET_DECOMPRESSOR_OPTIONS(options) \
68
+ brs_ext_decompressor_options_t decompressor_options; \
69
+ \
70
+ BRS_EXT_RESOLVE_OPTION(options, decompressor_options, BRS_EXT_OPTION_TYPE_BOOL, disable_ring_buffer_reallocation); \
71
+ BRS_EXT_RESOLVE_OPTION(options, decompressor_options, BRS_EXT_OPTION_TYPE_BOOL, large_window);
72
+
73
+ bool brs_ext_get_bool_option_value(VALUE options, const char* name);
70
74
  size_t brs_ext_get_size_option_value(VALUE options, const char* name);
71
75
 
72
- #define BRS_EXT_GET_BUFFER_LENGTH_OPTION(options, name) \
73
- size_t name = brs_ext_get_size_option_value(options, #name);
76
+ #define BRS_EXT_GET_BOOL_OPTION(options, name) size_t name = brs_ext_get_bool_option_value(options, #name);
77
+ #define BRS_EXT_GET_SIZE_OPTION(options, name) size_t name = brs_ext_get_size_option_value(options, #name);
74
78
 
75
79
  brs_ext_result_t brs_ext_set_compressor_options(BrotliEncoderState* state_ptr, brs_ext_compressor_options_t* options);
76
- brs_ext_result_t brs_ext_set_decompressor_options(BrotliDecoderState* state_ptr, brs_ext_decompressor_options_t* options);
80
+
81
+ brs_ext_result_t brs_ext_set_decompressor_options(
82
+ BrotliDecoderState* state_ptr,
83
+ brs_ext_decompressor_options_t* options);
77
84
 
78
85
  void brs_ext_option_exports(VALUE root_module);
79
86
 
@@ -5,15 +5,15 @@
5
5
 
6
6
  #include <brotli/encode.h>
7
7
  #include <brotli/types.h>
8
- #include <stdint.h>
9
- #include <stdlib.h>
10
8
 
11
9
  #include "brs_ext/buffer.h"
12
- #include "brs_ext/common.h"
13
10
  #include "brs_ext/error.h"
11
+ #include "brs_ext/gvl.h"
14
12
  #include "brs_ext/option.h"
15
13
  #include "ruby.h"
16
14
 
15
+ // -- initialization --
16
+
17
17
  static void free_compressor(brs_ext_compressor_t* compressor_ptr)
18
18
  {
19
19
  BrotliEncoderState* state_ptr = compressor_ptr->state_ptr;
@@ -21,7 +21,7 @@ static void free_compressor(brs_ext_compressor_t* compressor_ptr)
21
21
  BrotliEncoderDestroyInstance(state_ptr);
22
22
  }
23
23
 
24
- uint8_t* destination_buffer = compressor_ptr->destination_buffer;
24
+ brs_ext_byte_t* destination_buffer = compressor_ptr->destination_buffer;
25
25
  if (destination_buffer != NULL) {
26
26
  free(destination_buffer);
27
27
  }
@@ -32,14 +32,14 @@ static void free_compressor(brs_ext_compressor_t* compressor_ptr)
32
32
  VALUE brs_ext_allocate_compressor(VALUE klass)
33
33
  {
34
34
  brs_ext_compressor_t* compressor_ptr;
35
-
36
- VALUE self = Data_Make_Struct(klass, brs_ext_compressor_t, NULL, free_compressor, compressor_ptr);
35
+ VALUE self = Data_Make_Struct(klass, brs_ext_compressor_t, NULL, free_compressor, compressor_ptr);
37
36
 
38
37
  compressor_ptr->state_ptr = NULL;
39
38
  compressor_ptr->destination_buffer = NULL;
40
39
  compressor_ptr->destination_buffer_length = 0;
41
40
  compressor_ptr->remaining_destination_buffer = NULL;
42
41
  compressor_ptr->remaining_destination_buffer_length = 0;
42
+ compressor_ptr->gvl = false;
43
43
 
44
44
  return self;
45
45
  }
@@ -52,8 +52,9 @@ VALUE brs_ext_initialize_compressor(VALUE self, VALUE options)
52
52
  {
53
53
  GET_COMPRESSOR(self);
54
54
  Check_Type(options, T_HASH);
55
+ BRS_EXT_GET_SIZE_OPTION(options, destination_buffer_length);
56
+ BRS_EXT_GET_BOOL_OPTION(options, gvl);
55
57
  BRS_EXT_GET_COMPRESSOR_OPTIONS(options);
56
- BRS_EXT_GET_BUFFER_LENGTH_OPTION(options, destination_buffer_length);
57
58
 
58
59
  BrotliEncoderState* state_ptr = BrotliEncoderCreateInstance(NULL, NULL, NULL);
59
60
  if (state_ptr == NULL) {
@@ -70,7 +71,7 @@ VALUE brs_ext_initialize_compressor(VALUE self, VALUE options)
70
71
  destination_buffer_length = BRS_DEFAULT_DESTINATION_BUFFER_LENGTH_FOR_COMPRESSOR;
71
72
  }
72
73
 
73
- uint8_t* destination_buffer = malloc(destination_buffer_length);
74
+ brs_ext_byte_t* destination_buffer = malloc(destination_buffer_length);
74
75
  if (destination_buffer == NULL) {
75
76
  BrotliEncoderDestroyInstance(state_ptr);
76
77
  brs_ext_raise_error(BRS_EXT_ERROR_ALLOCATE_FAILED);
@@ -81,72 +82,137 @@ VALUE brs_ext_initialize_compressor(VALUE self, VALUE options)
81
82
  compressor_ptr->destination_buffer_length = destination_buffer_length;
82
83
  compressor_ptr->remaining_destination_buffer = destination_buffer;
83
84
  compressor_ptr->remaining_destination_buffer_length = destination_buffer_length;
85
+ compressor_ptr->gvl = gvl;
84
86
 
85
87
  return Qnil;
86
88
  }
87
89
 
90
+ // -- compress --
91
+
88
92
  #define DO_NOT_USE_AFTER_CLOSE(compressor_ptr) \
89
93
  if (compressor_ptr->state_ptr == NULL || compressor_ptr->destination_buffer == NULL) { \
90
94
  brs_ext_raise_error(BRS_EXT_ERROR_USED_AFTER_CLOSE); \
91
95
  }
92
96
 
93
- #define GET_SOURCE_DATA(source_value) \
94
- Check_Type(source_value, T_STRING); \
95
- \
96
- const char* source = RSTRING_PTR(source_value); \
97
- size_t source_length = RSTRING_LEN(source_value); \
98
- const uint8_t* remaining_source = (const uint8_t*)source; \
99
- size_t remaining_source_length = source_length;
97
+ typedef struct
98
+ {
99
+ brs_ext_compressor_t* compressor_ptr;
100
+ const brs_ext_byte_t* remaining_source;
101
+ size_t* remaining_source_length_ptr;
102
+ BROTLI_BOOL result;
103
+ } compress_args_t;
104
+
105
+ static inline void* compress_wrapper(void* data)
106
+ {
107
+ compress_args_t* args = data;
108
+ brs_ext_compressor_t* compressor_ptr = args->compressor_ptr;
109
+
110
+ args->result = BrotliEncoderCompressStream(
111
+ compressor_ptr->state_ptr,
112
+ BROTLI_OPERATION_PROCESS,
113
+ args->remaining_source_length_ptr,
114
+ &args->remaining_source,
115
+ &compressor_ptr->remaining_destination_buffer_length,
116
+ &compressor_ptr->remaining_destination_buffer,
117
+ NULL);
118
+
119
+ return NULL;
120
+ }
100
121
 
101
122
  VALUE brs_ext_compress(VALUE self, VALUE source_value)
102
123
  {
103
124
  GET_COMPRESSOR(self);
104
125
  DO_NOT_USE_AFTER_CLOSE(compressor_ptr);
105
- GET_SOURCE_DATA(source_value);
126
+ Check_Type(source_value, T_STRING);
106
127
 
107
- BrotliEncoderState* state_ptr = compressor_ptr->state_ptr;
128
+ const char* source = RSTRING_PTR(source_value);
129
+ size_t source_length = RSTRING_LEN(source_value);
130
+ const brs_ext_byte_t* remaining_source = (const brs_ext_byte_t*) source;
131
+ size_t remaining_source_length = source_length;
108
132
 
109
- BROTLI_BOOL result = BrotliEncoderCompressStream(
110
- state_ptr,
111
- BROTLI_OPERATION_PROCESS,
112
- &remaining_source_length, &remaining_source,
113
- &compressor_ptr->remaining_destination_buffer_length, &compressor_ptr->remaining_destination_buffer,
114
- NULL);
133
+ compress_args_t args = {
134
+ .compressor_ptr = compressor_ptr,
135
+ .remaining_source = remaining_source,
136
+ .remaining_source_length_ptr = &remaining_source_length};
115
137
 
116
- if (!result) {
138
+ BRS_EXT_GVL_WRAP(compressor_ptr->gvl, compress_wrapper, &args);
139
+ if (!args.result) {
117
140
  brs_ext_raise_error(BRS_EXT_ERROR_UNEXPECTED);
118
141
  }
119
142
 
120
143
  VALUE bytes_written = SIZET2NUM(source_length - remaining_source_length);
121
- VALUE needs_more_destination = BrotliEncoderHasMoreOutput(state_ptr) ? Qtrue : Qfalse;
144
+ VALUE needs_more_destination = BrotliEncoderHasMoreOutput(compressor_ptr->state_ptr) ? Qtrue : Qfalse;
122
145
 
123
146
  return rb_ary_new_from_args(2, bytes_written, needs_more_destination);
124
147
  }
125
148
 
126
- VALUE brs_ext_flush_compressor(VALUE self)
127
- {
128
- GET_COMPRESSOR(self);
129
- DO_NOT_USE_AFTER_CLOSE(compressor_ptr);
149
+ // -- compressor flush --
130
150
 
131
- BrotliEncoderState* state_ptr = compressor_ptr->state_ptr;
151
+ typedef struct
152
+ {
153
+ brs_ext_compressor_t* compressor_ptr;
154
+ BROTLI_BOOL result;
155
+ } compressor_flush_args_t;
132
156
 
133
- const uint8_t* remaining_source = NULL;
134
- size_t remaining_source_length = 0;
157
+ static inline void* compressor_flush_wrapper(void* data)
158
+ {
159
+ compressor_flush_args_t* args = data;
160
+ brs_ext_compressor_t* compressor_ptr = args->compressor_ptr;
161
+ const brs_ext_byte_t* remaining_source = NULL;
162
+ size_t remaining_source_length = 0;
135
163
 
136
- BROTLI_BOOL result = BrotliEncoderCompressStream(
137
- state_ptr,
164
+ args->result = BrotliEncoderCompressStream(
165
+ compressor_ptr->state_ptr,
138
166
  BROTLI_OPERATION_FLUSH,
139
- &remaining_source_length, &remaining_source,
140
- &compressor_ptr->remaining_destination_buffer_length, &compressor_ptr->remaining_destination_buffer,
167
+ &remaining_source_length,
168
+ &remaining_source,
169
+ &compressor_ptr->remaining_destination_buffer_length,
170
+ &compressor_ptr->remaining_destination_buffer,
141
171
  NULL);
142
172
 
143
- if (!result) {
173
+ return NULL;
174
+ }
175
+
176
+ VALUE brs_ext_flush_compressor(VALUE self)
177
+ {
178
+ GET_COMPRESSOR(self);
179
+ DO_NOT_USE_AFTER_CLOSE(compressor_ptr);
180
+
181
+ compressor_flush_args_t args = {.compressor_ptr = compressor_ptr};
182
+
183
+ BRS_EXT_GVL_WRAP(compressor_ptr->gvl, compressor_flush_wrapper, &args);
184
+ if (!args.result) {
144
185
  brs_ext_raise_error(BRS_EXT_ERROR_UNEXPECTED);
145
186
  }
146
187
 
147
- VALUE needs_more_destination = BrotliEncoderHasMoreOutput(state_ptr) ? Qtrue : Qfalse;
188
+ return BrotliEncoderHasMoreOutput(compressor_ptr->state_ptr) ? Qtrue : Qfalse;
189
+ }
190
+
191
+ // -- compressor finish --
148
192
 
149
- return needs_more_destination;
193
+ typedef struct
194
+ {
195
+ brs_ext_compressor_t* compressor_ptr;
196
+ BROTLI_BOOL result;
197
+ } compressor_finish_args_t;
198
+
199
+ static inline void* compressor_finish_wrapper(void* data)
200
+ {
201
+ compressor_finish_args_t* args = data;
202
+ brs_ext_compressor_t* compressor_ptr = args->compressor_ptr;
203
+ const brs_ext_byte_t* remaining_source = NULL;
204
+ size_t remaining_source_length = 0;
205
+
206
+ args->result = BrotliEncoderCompressStream(
207
+ compressor_ptr->state_ptr,
208
+ BROTLI_OPERATION_FINISH,
209
+ &remaining_source_length,
210
+ &remaining_source,
211
+ &compressor_ptr->remaining_destination_buffer_length,
212
+ &compressor_ptr->remaining_destination_buffer,
213
+ NULL);
214
+
215
+ return NULL;
150
216
  }
151
217
 
152
218
  VALUE brs_ext_finish_compressor(VALUE self)
@@ -154,40 +220,33 @@ VALUE brs_ext_finish_compressor(VALUE self)
154
220
  GET_COMPRESSOR(self);
155
221
  DO_NOT_USE_AFTER_CLOSE(compressor_ptr);
156
222
 
157
- BrotliEncoderState* state_ptr = compressor_ptr->state_ptr;
158
-
159
- const uint8_t* remaining_source = NULL;
160
- size_t remaining_source_length = 0;
161
-
162
- BROTLI_BOOL result = BrotliEncoderCompressStream(
163
- state_ptr,
164
- BROTLI_OPERATION_FINISH,
165
- &remaining_source_length, &remaining_source,
166
- &compressor_ptr->remaining_destination_buffer_length, &compressor_ptr->remaining_destination_buffer,
167
- NULL);
223
+ compressor_finish_args_t args = {.compressor_ptr = compressor_ptr};
168
224
 
169
- if (!result) {
225
+ BRS_EXT_GVL_WRAP(compressor_ptr->gvl, compressor_finish_wrapper, &args);
226
+ if (!args.result) {
170
227
  brs_ext_raise_error(BRS_EXT_ERROR_UNEXPECTED);
171
228
  }
172
229
 
173
- VALUE needs_more_destination = (BrotliEncoderHasMoreOutput(state_ptr) || !BrotliEncoderIsFinished(state_ptr)) ? Qtrue : Qfalse;
174
-
175
- return needs_more_destination;
230
+ return (BrotliEncoderHasMoreOutput(compressor_ptr->state_ptr) ||
231
+ !BrotliEncoderIsFinished(compressor_ptr->state_ptr)) ?
232
+ Qtrue :
233
+ Qfalse;
176
234
  }
177
235
 
236
+ // -- other --
237
+
178
238
  VALUE brs_ext_compressor_read_result(VALUE self)
179
239
  {
180
240
  GET_COMPRESSOR(self);
181
241
  DO_NOT_USE_AFTER_CLOSE(compressor_ptr);
182
242
 
183
- uint8_t* destination_buffer = compressor_ptr->destination_buffer;
184
- size_t destination_buffer_length = compressor_ptr->destination_buffer_length;
185
- size_t remaining_destination_buffer_length = compressor_ptr->remaining_destination_buffer_length;
243
+ brs_ext_byte_t* destination_buffer = compressor_ptr->destination_buffer;
244
+ size_t destination_buffer_length = compressor_ptr->destination_buffer_length;
245
+ size_t remaining_destination_buffer_length = compressor_ptr->remaining_destination_buffer_length;
186
246
 
187
- const char* result = (const char*)destination_buffer;
247
+ const char* result = (const char*) destination_buffer;
188
248
  size_t result_length = destination_buffer_length - remaining_destination_buffer_length;
189
-
190
- VALUE result_value = rb_str_new(result, result_length);
249
+ VALUE result_value = rb_str_new(result, result_length);
191
250
 
192
251
  compressor_ptr->remaining_destination_buffer = destination_buffer;
193
252
  compressor_ptr->remaining_destination_buffer_length = destination_buffer_length;
@@ -195,6 +254,8 @@ VALUE brs_ext_compressor_read_result(VALUE self)
195
254
  return result_value;
196
255
  }
197
256
 
257
+ // -- cleanup --
258
+
198
259
  VALUE brs_ext_compressor_close(VALUE self)
199
260
  {
200
261
  GET_COMPRESSOR(self);
@@ -207,7 +268,7 @@ VALUE brs_ext_compressor_close(VALUE self)
207
268
  compressor_ptr->state_ptr = NULL;
208
269
  }
209
270
 
210
- uint8_t* destination_buffer = compressor_ptr->destination_buffer;
271
+ brs_ext_byte_t* destination_buffer = compressor_ptr->destination_buffer;
211
272
  if (destination_buffer != NULL) {
212
273
  free(destination_buffer);
213
274
 
@@ -220,6 +281,8 @@ VALUE brs_ext_compressor_close(VALUE self)
220
281
  return Qnil;
221
282
  }
222
283
 
284
+ // -- exports --
285
+
223
286
  void brs_ext_compressor_exports(VALUE root_module)
224
287
  {
225
288
  VALUE module = rb_define_module_under(root_module, "Stream");