polyphony 0.87 → 0.89

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 938f929b8373ea094ae045c5acc830f6b848a5018bc5604eab280c740e72f56f
4
- data.tar.gz: e0806785ca3b5ea6101640b8bbfba9ece96f5c614e13267e07a1f15c33efeb1f
3
+ metadata.gz: 9b79252b4e1c8617c398d6804b93063b8d155d1b5d813b65cb2c9a2a1ce4e5e0
4
+ data.tar.gz: 619e0c77d6ed5bc3d4d0c33e143d5f18eaf83e34d5fc8fe576524a554843faeb
5
5
  SHA512:
6
- metadata.gz: db4f627ab9fd78899711f8eb12c359e038835ada7d43e494cf0377a2a7f6795746a1e877987f32934e94700cb536c27b58e53d7a5cf77161863a4d26c55abcb5
7
- data.tar.gz: f7ac358243a16baa8e83923cf46ac7d8ce422a9e0faeea28faa3e0dd523b6b666180fcf1f5182e86c534ced64cfe680895bcdf7bdc9f16e77b641940f439d992
6
+ metadata.gz: 137e6a8387305c160af5a59c7d7df91c18e09cd5ba954da3fcd78f339d877aa7d91430ae212852dc8bba5771e12cce4e6fa5b51350ebfb75cc3c61e979babf8c
7
+ data.tar.gz: 8f0bfeb1b9d05fd7b6494a17f23d79ecb28b825b0e37ace7be913a42eee589859320ebd904313f28e691eef0e5951109acca4be95dfe53156edc108c3dab060f
@@ -8,15 +8,19 @@ jobs:
8
8
  fail-fast: false
9
9
  matrix:
10
10
  os: [ubuntu-latest]
11
- ruby: [2.6, 2.7, 3.0]
11
+ ruby: ['2.7', '3.0', '3.1', 'head']
12
12
 
13
13
  name: >-
14
14
  ${{matrix.os}}, ${{matrix.ruby}}
15
15
 
16
16
  runs-on: ${{matrix.os}}
17
17
  steps:
18
- - uses: actions/checkout@v1
19
- - uses: ruby/setup-ruby@v1
18
+ - name: Checkout repository and submodules
19
+ uses: actions/checkout@v2
20
+ with:
21
+ submodules: recursive
22
+ - name: Setup Ruby
23
+ uses: ruby/setup-ruby@v1
20
24
  with:
21
25
  ruby-version: ${{matrix.ruby}}
22
26
  bundler-cache: true # 'bundle install' and cache
@@ -29,4 +33,4 @@ jobs:
29
33
  - name: Compile C-extension
30
34
  run: bundle exec rake compile
31
35
  - name: Run tests
32
- run: bundle exec rake test
36
+ run: bundle exec ruby test/run.rb --verbose --name test_sleep
data/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ ## 0.89 2022-03-21
2
+
3
+ - Implement compression/decompression to/from strings (#86)
4
+
5
+ ## 0.88 2022-03-18
6
+
7
+ - Improve IO stream compression utilities (release GVL, cleanup on exception)
8
+
1
9
  ## 0.87 2022-03-17
2
10
 
3
11
  - Fix compilation on non-Linux OSes
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- polyphony (0.87)
4
+ polyphony (0.89)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -363,8 +363,6 @@ inline void set_fd_blocking_mode(int fd, int blocking) {
363
363
  }
364
364
 
365
365
  inline void io_verify_blocking_mode(rb_io_t *fptr, VALUE io, VALUE blocking) {
366
- int flags;
367
- int is_nonblocking;
368
366
  VALUE blocking_mode = rb_ivar_get(io, ID_ivar_blocking_mode);
369
367
  if (blocking == blocking_mode) return;
370
368
 
@@ -481,7 +479,7 @@ struct io_buffer get_io_buffer(VALUE in) {
481
479
  struct raw_buffer *raw = FIX2PTR(in);
482
480
  return (struct io_buffer){ raw->ptr, raw->len, 1 };
483
481
  }
484
- return (struct io_buffer){ RSTRING_PTR(in), RSTRING_LEN(in), 0 };
482
+ return (struct io_buffer){ (unsigned char *)RSTRING_PTR(in), RSTRING_LEN(in), 0 };
485
483
  }
486
484
 
487
485
  VALUE coerce_io_string_or_buffer(VALUE buf) {
@@ -262,6 +262,22 @@ inline struct backend_stats backend_get_stats(VALUE self) {
262
262
  return backend_base_stats(&backend->base);
263
263
  }
264
264
 
265
+ static inline struct io_uring_sqe *io_uring_backend_get_sqe(Backend_t *backend) {
266
+ struct io_uring_sqe *sqe;
267
+ try:
268
+ sqe = io_uring_get_sqe(&backend->ring);
269
+ if (sqe) goto done;
270
+
271
+ if (backend->pending_sqes)
272
+ io_uring_backend_immediate_submit(backend);
273
+ else {
274
+ VALUE resume_value = backend_snooze(&backend->base);
275
+ RAISE_IF_EXCEPTION(resume_value);
276
+ }
277
+ done:
278
+ return sqe;
279
+ }
280
+
265
281
  VALUE Backend_wakeup(VALUE self) {
266
282
  Backend_t *backend;
267
283
  GetBackend(self, backend);
@@ -269,7 +285,7 @@ VALUE Backend_wakeup(VALUE self) {
269
285
  if (backend->base.currently_polling) {
270
286
  // Since we're currently blocking while waiting for a completion, we add a
271
287
  // NOP which would cause the io_uring_enter syscall to return
272
- struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
288
+ struct io_uring_sqe *sqe = io_uring_backend_get_sqe(backend);
273
289
  io_uring_prep_nop(sqe);
274
290
  io_uring_backend_immediate_submit(backend);
275
291
 
@@ -302,7 +318,7 @@ int io_uring_backend_defer_submit_and_await(
302
318
 
303
319
  // op was not completed (an exception was raised), so we need to cancel it
304
320
  ctx->result = -ECANCELED;
305
- sqe = io_uring_get_sqe(&backend->ring);
321
+ sqe = io_uring_backend_get_sqe(backend);
306
322
  io_uring_prep_cancel(sqe, (__u64)ctx, 0);
307
323
  io_uring_backend_immediate_submit(backend);
308
324
  }
@@ -317,7 +333,7 @@ VALUE io_uring_backend_wait_fd(Backend_t *backend, int fd, int write) {
317
333
  op_context_t *ctx = context_store_acquire(&backend->store, OP_POLL);
318
334
  VALUE resumed_value = Qnil;
319
335
 
320
- struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
336
+ struct io_uring_sqe *sqe = io_uring_backend_get_sqe(backend);
321
337
  io_uring_prep_poll_add(sqe, fd, write ? POLLOUT : POLLIN);
322
338
 
323
339
  io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resumed_value);
@@ -385,7 +401,7 @@ VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof,
385
401
  while (1) {
386
402
  VALUE resume_value = Qnil;
387
403
  op_context_t *ctx = context_store_acquire(&backend->store, OP_READ);
388
- struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
404
+ struct io_uring_sqe *sqe = io_uring_backend_get_sqe(backend);
389
405
  int result;
390
406
  int completed;
391
407
 
@@ -453,7 +469,7 @@ VALUE Backend_read_loop(VALUE self, VALUE io, VALUE maxlen) {
453
469
  while (1) {
454
470
  VALUE resume_value = Qnil;
455
471
  op_context_t *ctx = context_store_acquire(&backend->store, OP_READ);
456
- struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
472
+ struct io_uring_sqe *sqe = io_uring_backend_get_sqe(backend);
457
473
  ssize_t result;
458
474
  int completed;
459
475
 
@@ -502,7 +518,7 @@ VALUE Backend_feed_loop(VALUE self, VALUE io, VALUE receiver, VALUE method) {
502
518
  while (1) {
503
519
  VALUE resume_value = Qnil;
504
520
  op_context_t *ctx = context_store_acquire(&backend->store, OP_READ);
505
- struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
521
+ struct io_uring_sqe *sqe = io_uring_backend_get_sqe(backend);
506
522
  ssize_t result;
507
523
  int completed;
508
524
 
@@ -546,7 +562,7 @@ VALUE Backend_write(VALUE self, VALUE io, VALUE str) {
546
562
  while (left > 0) {
547
563
  VALUE resume_value = Qnil;
548
564
  op_context_t *ctx = context_store_acquire(&backend->store, OP_WRITE);
549
- struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
565
+ struct io_uring_sqe *sqe = io_uring_backend_get_sqe(backend);
550
566
  int result;
551
567
  int completed;
552
568
 
@@ -597,7 +613,7 @@ VALUE Backend_writev(VALUE self, VALUE io, int argc, VALUE *argv) {
597
613
  while (1) {
598
614
  VALUE resume_value = Qnil;
599
615
  op_context_t *ctx = context_store_acquire(&backend->store, OP_WRITEV);
600
- struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
616
+ struct io_uring_sqe *sqe = io_uring_backend_get_sqe(backend);
601
617
  int result;
602
618
  int completed;
603
619
 
@@ -689,7 +705,7 @@ VALUE Backend_recv(VALUE self, VALUE io, VALUE str, VALUE length, VALUE pos) {
689
705
  while (1) {
690
706
  VALUE resume_value = Qnil;
691
707
  op_context_t *ctx = context_store_acquire(&backend->store, OP_RECV);
692
- struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
708
+ struct io_uring_sqe *sqe = io_uring_backend_get_sqe(backend);
693
709
  int result;
694
710
  int completed;
695
711
 
@@ -739,7 +755,7 @@ VALUE Backend_recv_loop(VALUE self, VALUE io, VALUE maxlen) {
739
755
  while (1) {
740
756
  VALUE resume_value = Qnil;
741
757
  op_context_t *ctx = context_store_acquire(&backend->store, OP_RECV);
742
- struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
758
+ struct io_uring_sqe *sqe = io_uring_backend_get_sqe(backend);
743
759
  int result;
744
760
  int completed;
745
761
 
@@ -787,7 +803,7 @@ VALUE Backend_recv_feed_loop(VALUE self, VALUE io, VALUE receiver, VALUE method)
787
803
  while (1) {
788
804
  VALUE resume_value = Qnil;
789
805
  op_context_t *ctx = context_store_acquire(&backend->store, OP_RECV);
790
- struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
806
+ struct io_uring_sqe *sqe = io_uring_backend_get_sqe(backend);
791
807
  int result;
792
808
  int completed;
793
809
 
@@ -831,7 +847,7 @@ VALUE Backend_send(VALUE self, VALUE io, VALUE str, VALUE flags) {
831
847
  while (left > 0) {
832
848
  VALUE resume_value = Qnil;
833
849
  op_context_t *ctx = context_store_acquire(&backend->store, OP_SEND);
834
- struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
850
+ struct io_uring_sqe *sqe = io_uring_backend_get_sqe(backend);
835
851
  int result;
836
852
  int completed;
837
853
 
@@ -869,7 +885,7 @@ VALUE io_uring_backend_accept(Backend_t *backend, VALUE server_socket, VALUE soc
869
885
  while (1) {
870
886
  VALUE resume_value = Qnil;
871
887
  op_context_t *ctx = context_store_acquire(&backend->store, OP_ACCEPT);
872
- struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
888
+ struct io_uring_sqe *sqe = io_uring_backend_get_sqe(backend);
873
889
  int fd;
874
890
  int completed;
875
891
 
@@ -935,7 +951,7 @@ VALUE io_uring_backend_splice(Backend_t *backend, VALUE src, VALUE dest, VALUE m
935
951
 
936
952
  while (1) {
937
953
  op_context_t *ctx = context_store_acquire(&backend->store, OP_SPLICE);
938
- struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
954
+ struct io_uring_sqe *sqe = io_uring_backend_get_sqe(backend);
939
955
  int result;
940
956
  int completed;
941
957
 
@@ -984,7 +1000,7 @@ VALUE Backend_tee(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
984
1000
 
985
1001
  while (1) {
986
1002
  op_context_t *ctx = context_store_acquire(&backend->store, OP_SPLICE);
987
- struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
1003
+ struct io_uring_sqe *sqe = io_uring_backend_get_sqe(backend);
988
1004
  int result;
989
1005
  int completed;
990
1006
 
@@ -1021,7 +1037,7 @@ VALUE Backend_connect(VALUE self, VALUE sock, VALUE host, VALUE port) {
1021
1037
  GetBackend(self, backend);
1022
1038
  fd = fd_from_io(sock, &fptr, 1, 0);
1023
1039
  ctx = context_store_acquire(&backend->store, OP_CONNECT);
1024
- sqe = io_uring_get_sqe(&backend->ring);
1040
+ sqe = io_uring_backend_get_sqe(backend);
1025
1041
  io_uring_prep_connect(sqe, fd, ai_addr, ai_addrlen);
1026
1042
  result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
1027
1043
  completed = context_store_release(&backend->store, ctx);
@@ -1063,7 +1079,7 @@ VALUE Backend_wait_io(VALUE self, VALUE io, VALUE write) {
1063
1079
  // io_unset_nonblock(fptr, io);
1064
1080
 
1065
1081
  // ctx = context_store_acquire(&backend->store, OP_CLOSE);
1066
- // sqe = io_uring_get_sqe(&backend->ring);
1082
+ // sqe = io_uring_backend_get_sqe(backend);
1067
1083
  // io_uring_prep_close(sqe, fd);
1068
1084
  // result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
1069
1085
  // completed = context_store_release(&backend->store, ctx);
@@ -1094,7 +1110,7 @@ inline struct __kernel_timespec duration_to_timespec(VALUE duration) {
1094
1110
  // returns true if completed, 0 otherwise
1095
1111
  int io_uring_backend_submit_timeout_and_await(Backend_t *backend, double duration, VALUE *resume_value) {
1096
1112
  struct __kernel_timespec ts = double_to_timespec(duration);
1097
- struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
1113
+ struct io_uring_sqe *sqe = io_uring_backend_get_sqe(backend);
1098
1114
  op_context_t *ctx = context_store_acquire(&backend->store, OP_TIMEOUT);
1099
1115
 
1100
1116
  io_uring_prep_timeout(sqe, &ts, 0, 0);
@@ -1183,7 +1199,7 @@ VALUE Backend_timeout(int argc, VALUE *argv, VALUE self) {
1183
1199
  GetBackend(self, backend);
1184
1200
  timeout = rb_funcall(cTimeoutException, ID_new, 0);
1185
1201
 
1186
- sqe = io_uring_get_sqe(&backend->ring);
1202
+ sqe = io_uring_backend_get_sqe(backend);
1187
1203
  ctx = context_store_acquire(&backend->store, OP_TIMEOUT);
1188
1204
  ctx->resume_value = timeout;
1189
1205
  io_uring_prep_timeout(sqe, &ts, 0, 0);
@@ -1259,7 +1275,7 @@ VALUE Backend_wait_event(VALUE self, VALUE raise) {
1259
1275
  struct io_uring_sqe *sqe;
1260
1276
 
1261
1277
  backend->event_fd_ctx = context_store_acquire(&backend->store, OP_POLL);
1262
- sqe = io_uring_get_sqe(&backend->ring);
1278
+ sqe = io_uring_backend_get_sqe(backend);
1263
1279
  io_uring_prep_poll_add(sqe, backend->event_fd, POLLIN);
1264
1280
  backend->base.op_count++;
1265
1281
  io_uring_sqe_set_data(sqe, backend->event_fd_ctx);
@@ -1275,7 +1291,7 @@ VALUE Backend_wait_event(VALUE self, VALUE raise) {
1275
1291
 
1276
1292
  // last fiber to use the eventfd, so we cancel the ongoing poll
1277
1293
  struct io_uring_sqe *sqe;
1278
- sqe = io_uring_get_sqe(&backend->ring);
1294
+ sqe = io_uring_backend_get_sqe(backend);
1279
1295
  io_uring_prep_cancel(sqe, (__u64)backend->event_fd_ctx, 0);
1280
1296
  io_uring_backend_immediate_submit(backend);
1281
1297
  backend->event_fd_ctx = NULL;
@@ -1296,7 +1312,7 @@ struct io_uring_sqe *Backend_chain_prepare_write(Backend_t *backend, VALUE io, V
1296
1312
  struct io_uring_sqe *sqe;
1297
1313
 
1298
1314
  fd = fd_from_io(io, &fptr, 1, 0);
1299
- sqe = io_uring_get_sqe(&backend->ring);
1315
+ sqe = io_uring_backend_get_sqe(backend);
1300
1316
  io_uring_prep_write(sqe, fd, StringValuePtr(str), RSTRING_LEN(str), 0);
1301
1317
  return sqe;
1302
1318
  }
@@ -1308,7 +1324,7 @@ struct io_uring_sqe *Backend_chain_prepare_send(Backend_t *backend, VALUE io, VA
1308
1324
 
1309
1325
  fd = fd_from_io(io, &fptr, 1, 0);
1310
1326
 
1311
- sqe = io_uring_get_sqe(&backend->ring);
1327
+ sqe = io_uring_backend_get_sqe(backend);
1312
1328
  io_uring_prep_send(sqe, fd, StringValuePtr(str), RSTRING_LEN(str), NUM2INT(flags));
1313
1329
  return sqe;
1314
1330
  }
@@ -1322,7 +1338,7 @@ struct io_uring_sqe *Backend_chain_prepare_splice(Backend_t *backend, VALUE src,
1322
1338
 
1323
1339
  src_fd = fd_from_io(src, &src_fptr, 0, 0);
1324
1340
  dest_fd = fd_from_io(dest, &dest_fptr, 1, 0);
1325
- sqe = io_uring_get_sqe(&backend->ring);
1341
+ sqe = io_uring_backend_get_sqe(backend);
1326
1342
  io_uring_prep_splice(sqe, src_fd, -1, dest_fd, -1, NUM2INT(maxlen), 0);
1327
1343
  return sqe;
1328
1344
  }
@@ -1381,7 +1397,7 @@ VALUE Backend_chain(int argc,VALUE *argv, VALUE self) {
1381
1397
 
1382
1398
  ctx->ref_count = sqe_count;
1383
1399
  ctx->result = -ECANCELED;
1384
- sqe = io_uring_get_sqe(&backend->ring);
1400
+ sqe = io_uring_backend_get_sqe(backend);
1385
1401
  io_uring_prep_cancel(sqe, (__u64)ctx, 0);
1386
1402
  io_uring_backend_immediate_submit(backend);
1387
1403
  }
@@ -1411,7 +1427,7 @@ VALUE Backend_chain(int argc,VALUE *argv, VALUE self) {
1411
1427
 
1412
1428
  // op was not completed (an exception was raised), so we need to cancel it
1413
1429
  ctx->result = -ECANCELED;
1414
- sqe = io_uring_get_sqe(&backend->ring);
1430
+ sqe = io_uring_backend_get_sqe(backend);
1415
1431
  io_uring_prep_cancel(sqe, (__u64)ctx, 0);
1416
1432
  io_uring_backend_immediate_submit(backend);
1417
1433
  RAISE_IF_EXCEPTION(resume_value);
@@ -1470,14 +1486,14 @@ static inline void splice_chunks_get_sqe(
1470
1486
  }
1471
1487
  else
1472
1488
  *ctx = context_store_acquire(&backend->store, type);
1473
- (*sqe) = io_uring_get_sqe(&backend->ring);
1489
+ (*sqe) = io_uring_backend_get_sqe(backend);
1474
1490
  }
1475
1491
 
1476
1492
  static inline void splice_chunks_cancel(Backend_t *backend, op_context_t *ctx) {
1477
1493
  struct io_uring_sqe *sqe;
1478
1494
 
1479
1495
  ctx->result = -ECANCELED;
1480
- sqe = io_uring_get_sqe(&backend->ring);
1496
+ sqe = io_uring_backend_get_sqe(backend);
1481
1497
  io_uring_prep_cancel(sqe, (__u64)ctx, 0);
1482
1498
  io_uring_backend_immediate_submit(backend);
1483
1499
  }
@@ -47,6 +47,7 @@ end
47
47
  $defs << '-DPOLYPHONY_USE_PIDFD_OPEN' if config[:pidfd_open]
48
48
  if config[:io_uring]
49
49
  $defs << "-DPOLYPHONY_BACKEND_LIBURING"
50
+ $defs << "-DPOLYPHONY_LINUX"
50
51
  $defs << "-DPOLYPHONY_UNSET_NONBLOCK" if RUBY_VERSION =~ /^3/
51
52
  $CFLAGS << " -Wno-pointer-arith"
52
53
  else
@@ -10,6 +10,7 @@
10
10
  #include "polyphony.h"
11
11
  #include "zlib.h"
12
12
  #include "assert.h"
13
+ #include "ruby/thread.h"
13
14
 
14
15
  ID ID_at;
15
16
  ID ID_read_method;
@@ -29,6 +30,7 @@ VALUE SYM_orig_name;
29
30
  VALUE SYM_readpartial;
30
31
 
31
32
  enum read_method {
33
+ RM_STRING,
32
34
  RM_BACKEND_READ,
33
35
  RM_BACKEND_RECV,
34
36
  RM_READPARTIAL,
@@ -36,13 +38,15 @@ enum read_method {
36
38
  };
37
39
 
38
40
  enum write_method {
41
+ WM_STRING,
39
42
  WM_BACKEND_WRITE,
40
43
  WM_BACKEND_SEND,
41
44
  WM_WRITE,
42
45
  WM_CALL
43
46
  };
44
47
 
45
- static enum read_method detect_read_method(VALUE io) {
48
+ static inline enum read_method detect_read_method(VALUE io) {
49
+ if (TYPE(io) == T_STRING) return RM_STRING;
46
50
  if (rb_respond_to(io, ID_read_method)) {
47
51
  VALUE method = rb_funcall(io, ID_read_method, 0);
48
52
  if (method == SYM_readpartial) return RM_READPARTIAL;
@@ -58,7 +62,8 @@ static enum read_method detect_read_method(VALUE io) {
58
62
  rb_raise(rb_eRuntimeError, "Given io instance should be a callable or respond to #__read_method__");
59
63
  }
60
64
 
61
- static enum write_method detect_write_method(VALUE io) {
65
+ static inline enum write_method detect_write_method(VALUE io) {
66
+ if (TYPE(io) == T_STRING) return WM_STRING;
62
67
  if (rb_respond_to(io, ID_write_method)) {
63
68
  VALUE method = rb_funcall(io, ID_write_method, 0);
64
69
  if (method == SYM_readpartial) return WM_WRITE;
@@ -136,11 +141,18 @@ static inline int read_to_raw_buffer(VALUE backend, VALUE io, enum read_method m
136
141
  RB_GC_GUARD(str);
137
142
  return len;
138
143
  }
144
+ default: {
145
+ rb_raise(rb_eRuntimeError, "Invalid read method");
146
+ }
139
147
  }
140
148
  }
141
149
 
142
150
  static inline int write_from_raw_buffer(VALUE backend, VALUE io, enum write_method method, struct raw_buffer *buffer) {
143
151
  switch (method) {
152
+ case WM_STRING: {
153
+ rb_str_buf_cat(io, (char *)buffer->ptr, buffer->len);
154
+ return buffer->len;
155
+ }
144
156
  case WM_BACKEND_WRITE: {
145
157
  VALUE len = Backend_write(backend, io, PTR2FIX(buffer));
146
158
  return FIX2INT(len);
@@ -165,6 +177,9 @@ static inline int write_from_raw_buffer(VALUE backend, VALUE io, enum write_meth
165
177
  RB_GC_GUARD(str);
166
178
  return buffer->len;
167
179
  }
180
+ default: {
181
+ rb_raise(rb_eRuntimeError, "Invalid write method");
182
+ }
168
183
  }
169
184
  }
170
185
 
@@ -228,7 +243,7 @@ static inline time_t time_from_object(VALUE o) {
228
243
  return FIX2INT(rb_funcall(o, rb_intern("to_i"), 0));
229
244
  }
230
245
 
231
- int gzip_prepare_header(struct gzip_header_ctx *ctx, char *buffer, int maxlen) {
246
+ int gzip_prepare_header(struct gzip_header_ctx *ctx, unsigned char *buffer, int maxlen) {
232
247
  int len = 0;
233
248
  unsigned char flags = 0, extraflags = 0;
234
249
 
@@ -259,7 +274,7 @@ int gzip_prepare_header(struct gzip_header_ctx *ctx, char *buffer, int maxlen) {
259
274
  return len;
260
275
  }
261
276
 
262
- int gzip_prepare_footer(unsigned long crc32, unsigned long total_in, char *buffer, int maxlen) {
277
+ static inline int gzip_prepare_footer(unsigned long crc32, unsigned long total_in, unsigned char *buffer, int maxlen) {
263
278
  assert(maxlen >= GZIP_FOOTER_LEN);
264
279
 
265
280
  gzfile_set32(crc32, buffer);
@@ -287,8 +302,8 @@ struct z_stream_ctx {
287
302
 
288
303
  unsigned char in[CHUNK];
289
304
  unsigned char out[CHUNK];
290
- int in_pos;
291
- int out_pos;
305
+ unsigned int in_pos;
306
+ unsigned int out_pos;
292
307
  unsigned long in_total;
293
308
  unsigned long out_total;
294
309
 
@@ -297,8 +312,8 @@ struct z_stream_ctx {
297
312
 
298
313
  typedef int (*zlib_func)(z_streamp, int);
299
314
 
300
- void read_gzip_header_str(struct raw_buffer *buffer, VALUE *str, int *in_pos, unsigned long *total_read) {
301
- int null_pos;
315
+ void read_gzip_header_str(struct raw_buffer *buffer, VALUE *str, unsigned int *in_pos, unsigned long *total_read) {
316
+ unsigned long null_pos;
302
317
  // find null terminator
303
318
  for (null_pos = *in_pos; null_pos < *total_read; null_pos++) {
304
319
  if (!buffer->ptr[null_pos]) break;
@@ -306,28 +321,37 @@ void read_gzip_header_str(struct raw_buffer *buffer, VALUE *str, int *in_pos, un
306
321
  if (null_pos == *total_read)
307
322
  rb_raise(rb_eRuntimeError, "Invalid gzip header");
308
323
 
309
- *str = rb_str_new_cstr(buffer->ptr + *in_pos);
324
+ *str = rb_str_new_cstr((char *)buffer->ptr + *in_pos);
310
325
  *in_pos = null_pos + 1;
311
326
  }
312
327
 
313
328
  void gzip_read_header(struct z_stream_ctx *ctx, struct gzip_header_ctx *header_ctx) {
314
- struct raw_buffer in_buffer = { ctx->in, CHUNK };
329
+ struct raw_buffer in_buffer;
315
330
  int flags;
316
331
 
317
- while (ctx->in_total < 10) {
318
- int read = read_to_raw_buffer(ctx->backend, ctx->src, ctx->src_read_method, &in_buffer);
319
- if (read == 0) goto error;
320
- ctx->in_total += read;
332
+ if (ctx->src_read_method == RM_STRING) {
333
+ in_buffer.ptr = (unsigned char *)RSTRING_PTR(ctx->src);
334
+ in_buffer.len = RSTRING_LEN(ctx->src);
335
+ ctx->in_total = in_buffer.len;
336
+ }
337
+ else {
338
+ in_buffer.ptr = ctx->in;
339
+ in_buffer.len = CHUNK;
340
+ while (ctx->in_total < 10) {
341
+ int read = read_to_raw_buffer(ctx->backend, ctx->src, ctx->src_read_method, &in_buffer);
342
+ if (read == 0) goto error;
343
+ ctx->in_total += read;
344
+ }
321
345
  }
346
+
322
347
  // PRINT_BUFFER("read gzip header", ctx->in, ctx->in_total);
323
- if (ctx->in[0] != GZ_MAGIC1) goto error;
324
- if (ctx->in[1] != GZ_MAGIC2) goto error;
325
- if (ctx->in[2] != GZ_METHOD_DEFLATE) goto error;
326
- flags = ctx->in[3];
348
+ if (in_buffer.ptr[0] != GZ_MAGIC1) goto error;
349
+ if (in_buffer.ptr[1] != GZ_MAGIC2) goto error;
350
+ if (in_buffer.ptr[2] != GZ_METHOD_DEFLATE) goto error;
351
+ flags = in_buffer.ptr[3];
327
352
 
328
- unsigned long mtime = gzfile_get32(ctx->in + 4);
353
+ unsigned long mtime = gzfile_get32(in_buffer.ptr + 4);
329
354
  header_ctx->mtime = INT2FIX(mtime);
330
-
331
355
  ctx->in_pos = 10;
332
356
 
333
357
  if (flags & GZ_FLAG_ORIG_NAME)
@@ -344,6 +368,26 @@ error:
344
368
  rb_raise(rb_eRuntimeError, "Invalid gzip header");
345
369
  }
346
370
 
371
+ struct process_z_stream_ctx {
372
+ z_stream *strm;
373
+ int flags;
374
+ zlib_func fun;
375
+ int ret;
376
+ };
377
+
378
+ void *do_process_z_stream_without_gvl(void *ptr) {
379
+ struct process_z_stream_ctx *ctx = (struct process_z_stream_ctx *)ptr;
380
+
381
+ ctx->ret = (ctx->fun)(ctx->strm, ctx->flags);
382
+ return NULL;
383
+ }
384
+
385
+ static inline int process_without_gvl(zlib_func fun, z_stream *strm, int flags) {
386
+ struct process_z_stream_ctx ctx = { strm, flags, fun, 0 };
387
+ rb_thread_call_without_gvl2(do_process_z_stream_without_gvl, (void *)&ctx, RUBY_UBF_IO, 0);
388
+ return ctx.ret;
389
+ }
390
+
347
391
  static inline int z_stream_write_out(struct z_stream_ctx *ctx, zlib_func fun, int eof) {
348
392
  int ret;
349
393
  int written;
@@ -351,7 +395,7 @@ static inline int z_stream_write_out(struct z_stream_ctx *ctx, zlib_func fun, in
351
395
 
352
396
  int avail_out_pre = ctx->strm.avail_out = CHUNK - ctx->out_pos;
353
397
  ctx->strm.next_out = ctx->out + ctx->out_pos;
354
- ret = fun(&ctx->strm, eof ? Z_FINISH : Z_NO_FLUSH);
398
+ ret = process_without_gvl(fun, &ctx->strm, eof ? Z_FINISH : Z_NO_FLUSH);
355
399
  assert(ret != Z_STREAM_ERROR);
356
400
  written = avail_out_pre - ctx->strm.avail_out;
357
401
  out_buffer.ptr = ctx->out;
@@ -372,12 +416,13 @@ static inline int z_stream_write_out(struct z_stream_ctx *ctx, zlib_func fun, in
372
416
  return ctx->strm.avail_out;
373
417
  }
374
418
 
375
- void z_stream_io_loop(struct z_stream_ctx *ctx) {
419
+ VALUE z_stream_io_loop(struct z_stream_ctx *ctx) {
376
420
  zlib_func fun = (ctx->mode == SM_DEFLATE) ? deflate : inflate;
377
421
 
378
- if (ctx->in_total > ctx->in_pos) {
422
+ if ((ctx->src_read_method != RM_STRING) && (ctx->in_total > ctx->in_pos)) {
379
423
  // In bytes already read for parsing gzip header, so we need to process the
380
424
  // rest.
425
+
381
426
  ctx->strm.next_in = ctx->in + ctx->in_pos;
382
427
  ctx->strm.avail_in = ctx->in_total -= ctx->in_pos;
383
428
 
@@ -389,14 +434,27 @@ void z_stream_io_loop(struct z_stream_ctx *ctx) {
389
434
  }
390
435
 
391
436
  while (1) {
392
- struct raw_buffer in_buffer = {ctx->in, CHUNK};
393
- ctx->strm.next_in = ctx->in;
394
- int read_len = ctx->strm.avail_in = read_to_raw_buffer(ctx->backend, ctx->src, ctx->src_read_method, &in_buffer);
395
- if (!read_len) break;
396
- int eof = read_len < CHUNK;
397
-
398
- if (ctx->mode == SM_DEFLATE)
399
- ctx->crc32 = crc32(ctx->crc32, ctx->in, read_len);
437
+ int eof;
438
+ int read_len;
439
+ if (ctx->src_read_method == RM_STRING) {
440
+ struct raw_buffer in_buffer = {
441
+ (unsigned char *)RSTRING_PTR(ctx->src) + ctx->in_pos,
442
+ RSTRING_LEN(ctx->src) - ctx->in_pos
443
+ };
444
+ ctx->strm.next_in = in_buffer.ptr;
445
+ read_len = ctx->strm.avail_in = in_buffer.len;
446
+ eof = 1;
447
+ if (ctx->mode == SM_DEFLATE) ctx->crc32 = crc32(ctx->crc32, in_buffer.ptr, read_len);
448
+ }
449
+ else {
450
+ struct raw_buffer in_buffer = {ctx->in, CHUNK};
451
+ ctx->strm.next_in = ctx->in;
452
+ read_len = ctx->strm.avail_in = read_to_raw_buffer(ctx->backend, ctx->src, ctx->src_read_method, &in_buffer);
453
+ if (!read_len) break;
454
+ eof = read_len < CHUNK;
455
+ if (ctx->mode == SM_DEFLATE) ctx->crc32 = crc32(ctx->crc32, ctx->in, read_len);
456
+ }
457
+
400
458
  ctx->in_total += read_len;
401
459
 
402
460
  // PRINT_BUFFER("read stream", ctx->in, read_len);
@@ -407,13 +465,15 @@ void z_stream_io_loop(struct z_stream_ctx *ctx) {
407
465
  if (z_stream_write_out(ctx, fun, eof)) break;
408
466
  }
409
467
 
410
- if (eof) return;
468
+ if (eof) goto done;
411
469
  }
412
470
 
413
471
  //flush
414
472
  ctx->strm.avail_in = 0;
415
473
  ctx->strm.next_in = ctx->in;
416
474
  z_stream_write_out(ctx, fun, 1);
475
+ done:
476
+ return Qnil;
417
477
  }
418
478
 
419
479
  static inline void setup_ctx(struct z_stream_ctx *ctx, enum stream_mode mode, VALUE src, VALUE dest) {
@@ -434,6 +494,18 @@ static inline void setup_ctx(struct z_stream_ctx *ctx, enum stream_mode mode, VA
434
494
  ctx->crc32 = 0;
435
495
  }
436
496
 
497
+ static inline VALUE z_stream_cleanup(struct z_stream_ctx *ctx) {
498
+ if (ctx->mode == SM_DEFLATE)
499
+ deflateEnd(&ctx->strm);
500
+ else
501
+ inflateEnd(&ctx->strm);
502
+ return Qnil;
503
+ }
504
+
505
+ #define SAFE(f) (VALUE (*)(VALUE))(f)
506
+ #define Z_STREAM_SAFE_IO_LOOP_WITH_CLEANUP(ctx) \
507
+ rb_ensure(SAFE(z_stream_io_loop), (VALUE)&ctx, SAFE(z_stream_cleanup), (VALUE)&ctx)
508
+
437
509
  VALUE IO_gzip(int argc, VALUE *argv, VALUE self) {
438
510
  VALUE src;
439
511
  VALUE dest;
@@ -450,18 +522,16 @@ VALUE IO_gzip(int argc, VALUE *argv, VALUE self) {
450
522
  };
451
523
 
452
524
  struct z_stream_ctx ctx;
453
- int level = DEFAULT_LEVEL;
454
525
  int ret;
455
526
 
456
527
  setup_ctx(&ctx, SM_DEFLATE, src, dest);
457
528
  ctx.f_gzip_footer = 1; // write gzip footer
458
- ctx.out_pos = gzip_prepare_header(&header_ctx, ctx.out, sizeof(ctx.out));
529
+ ctx.out_total = ctx.out_pos = gzip_prepare_header(&header_ctx, ctx.out, sizeof(ctx.out));
459
530
 
460
- ret = deflateInit2(&ctx.strm, level, Z_DEFLATED, -MAX_WBITS, DEFAULT_MEM_LEVEL, Z_DEFAULT_STRATEGY);
461
- if (ret != Z_OK) return INT2FIX(ret);
462
- z_stream_io_loop(&ctx);
463
- deflateEnd(&ctx.strm);
464
-
531
+ ret = deflateInit2(&ctx.strm, DEFAULT_LEVEL, Z_DEFLATED, -MAX_WBITS, DEFAULT_MEM_LEVEL, Z_DEFAULT_STRATEGY);
532
+ if (ret != Z_OK)
533
+ rb_raise(rb_eRuntimeError, "zlib error: %s\n", ctx.strm.msg);
534
+ Z_STREAM_SAFE_IO_LOOP_WITH_CLEANUP(ctx);
465
535
  return INT2FIX(ctx.out_total);
466
536
  }
467
537
 
@@ -482,21 +552,25 @@ VALUE IO_gunzip(int argc, VALUE *argv, VALUE self) {
482
552
  setup_ctx(&ctx, SM_INFLATE, src, dest);
483
553
  gzip_read_header(&ctx, &header_ctx);
484
554
 
555
+ ret = inflateInit2(&ctx.strm, -MAX_WBITS);
556
+ if (ret != Z_OK)
557
+ rb_raise(rb_eRuntimeError, "zlib error: %s\n", ctx.strm.msg);
558
+
559
+ Z_STREAM_SAFE_IO_LOOP_WITH_CLEANUP(ctx);
560
+
561
+ // gzip_read_footer(&ctx, &footer_ctx);
562
+ // TODO: verify crc32
563
+ // TODO: verify total length
564
+
485
565
  if (info != Qnil) {
486
566
  rb_hash_aset(info, SYM_mtime, FIX2TIME(header_ctx.mtime));
487
567
  rb_hash_aset(info, SYM_orig_name, header_ctx.orig_name);
488
568
  rb_hash_aset(info, SYM_comment, header_ctx.comment);
489
569
  }
570
+ RB_GC_GUARD(header_ctx.orig_name);
571
+ RB_GC_GUARD(header_ctx.comment);
490
572
 
491
- ret = inflateInit2(&ctx.strm, -MAX_WBITS);
492
- if (ret != Z_OK) return INT2FIX(ret);
493
- z_stream_io_loop(&ctx);
494
- inflateEnd(&ctx.strm);
495
-
496
- // gzip_read_footer(&ctx, &footer_ctx);
497
- // TODO: verify crc32
498
- // TODO: verify total length
499
- return self;
573
+ return INT2FIX(ctx.out_total);
500
574
  }
501
575
 
502
576
  VALUE IO_deflate(VALUE self, VALUE src, VALUE dest) {
@@ -506,9 +580,10 @@ VALUE IO_deflate(VALUE self, VALUE src, VALUE dest) {
506
580
 
507
581
  setup_ctx(&ctx, SM_DEFLATE, src, dest);
508
582
  ret = deflateInit(&ctx.strm, level);
509
- if (ret != Z_OK) return INT2FIX(ret);
510
- z_stream_io_loop(&ctx);
511
- deflateEnd(&ctx.strm);
583
+ if (ret != Z_OK)
584
+ rb_raise(rb_eRuntimeError, "zlib error: %s\n", ctx.strm.msg);
585
+
586
+ Z_STREAM_SAFE_IO_LOOP_WITH_CLEANUP(ctx);
512
587
 
513
588
  return INT2FIX(ctx.out_total);
514
589
  }
@@ -519,9 +594,10 @@ VALUE IO_inflate(VALUE self, VALUE src, VALUE dest) {
519
594
 
520
595
  setup_ctx(&ctx, SM_INFLATE, src, dest);
521
596
  ret = inflateInit(&ctx.strm);
522
- if (ret != Z_OK) return INT2FIX(ret);
523
- z_stream_io_loop(&ctx);
524
- inflateEnd(&ctx.strm);
597
+ if (ret != Z_OK)
598
+ rb_raise(rb_eRuntimeError, "zlib error: %s\n", ctx.strm.msg);
599
+
600
+ Z_STREAM_SAFE_IO_LOOP_WITH_CLEANUP(ctx);
525
601
 
526
602
  return INT2FIX(ctx.out_total);
527
603
  }
@@ -538,16 +614,16 @@ VALUE IO_http1_splice_chunked(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
538
614
  if (!len) break;
539
615
 
540
616
  // write chunk header
541
- buffer.len += sprintf(buffer.ptr + buffer.len, "%x\r\n", len);
617
+ buffer.len += sprintf((char *)buffer.ptr + buffer.len, "%x\r\n", len);
542
618
  write_from_raw_buffer(backend, dest, method, &buffer);
543
619
  buffer.len = 0;
544
620
  while (len) {
545
621
  int spliced = FIX2INT(Backend_splice(backend, pipe, dest, INT2FIX(len)));
546
622
  len -= spliced;
547
623
  }
548
- buffer.len += sprintf(buffer.ptr + buffer.len, "\r\n");
624
+ buffer.len += sprintf((char *)buffer.ptr + buffer.len, "\r\n");
549
625
  }
550
- buffer.len += sprintf(buffer.ptr + buffer.len, "0\r\n\r\n");
626
+ buffer.len += sprintf((char *)buffer.ptr + buffer.len, "0\r\n\r\n");
551
627
  write_from_raw_buffer(backend, dest, method, &buffer);
552
628
 
553
629
  Pipe_close(pipe);
@@ -145,7 +145,7 @@ VALUE Polyphony_raw_buffer_get(int argc, VALUE *argv, VALUE self) {
145
145
  int length = (len == Qnil) ? buffer->len : FIX2INT(len);
146
146
 
147
147
  if (length > buffer->len) length = buffer->len;
148
- return rb_utf8_str_new(buffer->ptr, length);
148
+ return rb_utf8_str_new((char *)buffer->ptr, length);
149
149
  }
150
150
 
151
151
  VALUE Polyphony_raw_buffer_set(VALUE self, VALUE buf, VALUE str) {
@@ -164,12 +164,6 @@ VALUE Polyphony_raw_buffer_size(VALUE self, VALUE buf) {
164
164
  return INT2FIX(buffer->len);
165
165
  }
166
166
 
167
- VALUE Polyphony_backend_test(VALUE self, VALUE io, VALUE str) {
168
- struct raw_buffer buffer = { RSTRING_PTR(str), RSTRING_LEN(str) };
169
- VALUE args[2] = { io, PTR2FIX(&buffer) };
170
- return Polyphony_backend_write(2, args, self);
171
- }
172
-
173
167
  // VALUE Polyphony_backend_close(VALUE self, VALUE io) {
174
168
  // return Backend_close(BACKEND(), io);
175
169
  // }
@@ -210,7 +204,6 @@ void Init_Polyphony() {
210
204
  rb_define_singleton_method(mPolyphony, "__raw_buffer_get__", Polyphony_raw_buffer_get, -1);
211
205
  rb_define_singleton_method(mPolyphony, "__raw_buffer_set__", Polyphony_raw_buffer_set, 2);
212
206
  rb_define_singleton_method(mPolyphony, "__raw_buffer_size__", Polyphony_raw_buffer_size, 1);
213
- rb_define_singleton_method(mPolyphony, "backend_test", Polyphony_backend_test, 2);
214
207
 
215
208
  rb_define_global_function("snooze", Polyphony_snooze, 0);
216
209
  rb_define_global_function("suspend", Polyphony_suspend, 0);
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Polyphony
4
- VERSION = '0.87'
4
+ VERSION = '0.89'
5
5
  end
data/test/test_io.rb CHANGED
@@ -656,19 +656,75 @@ class IOExtensionsTest < MiniTest::Test
656
656
  i, o = IO.pipe
657
657
  r, w = IO.pipe
658
658
 
659
- spin {
660
- IO.deflate(i, w)
659
+ ret = nil
660
+ f = spin {
661
+ ret = IO.deflate(i, w)
661
662
  w.close
662
663
  }
663
664
 
664
665
  o << 'foobar' * 20
665
666
  o.close
666
667
 
668
+ f.await
669
+ assert_equal 17, ret
670
+
667
671
  data = r.read
668
672
  msg = Zlib::Inflate.inflate(data)
669
673
  assert_equal 'foobar' * 20, msg
670
674
  end
671
675
 
676
+ def test_deflate_to_string
677
+ i, o = IO.pipe
678
+ r, w = IO.pipe
679
+ str = +''
680
+
681
+ ret = nil
682
+ f = spin {
683
+ ret = IO.deflate(i, str)
684
+ w << str
685
+ w.close
686
+ }
687
+
688
+ o << 'foobar' * 20
689
+ o.close
690
+
691
+ f.await
692
+ assert_equal 17, ret
693
+
694
+ data = r.read
695
+ msg = Zlib::Inflate.inflate(data)
696
+ assert_equal 'foobar' * 20, msg
697
+ end
698
+
699
+ def test_deflate_to_frozen_string
700
+ i, o = IO.pipe
701
+ str = '' # frozen
702
+
703
+ f = spin {
704
+ o << 'foobar' * 20
705
+ o.close
706
+ }
707
+
708
+ assert_raises(FrozenError) { IO.deflate(i, str) }
709
+ end
710
+
711
+ def test_deflate_from_string
712
+ r, w = IO.pipe
713
+ str = 'foobar' * 10000
714
+ ret = nil
715
+
716
+ f = spin {
717
+ ret = IO.deflate(str, w)
718
+ w.close
719
+ }
720
+ f.await
721
+ assert_equal 118, ret
722
+
723
+ data = r.read
724
+ msg = Zlib::Inflate.inflate(data)
725
+ assert_equal str, msg
726
+ end
727
+
672
728
  def test_inflate
673
729
  i, o = IO.pipe
674
730
  r, w = IO.pipe
@@ -679,7 +735,35 @@ class IOExtensionsTest < MiniTest::Test
679
735
  o.close
680
736
  }
681
737
 
682
- IO.inflate(i, w)
738
+ ret = IO.inflate(i, w)
739
+ assert_equal 6, ret
740
+ w.close
741
+ msg = r.read
742
+ assert_equal 'foobar', msg
743
+ end
744
+
745
+ def test_inflate_to_string
746
+ i, o = IO.pipe
747
+ str = +''
748
+
749
+ spin {
750
+ data = Zlib::Deflate.deflate('foobar', 9)
751
+ o << data
752
+ o.close
753
+ }
754
+
755
+ ret = IO.inflate(i, str)
756
+ assert_equal 6, ret
757
+ assert_equal 6, str.bytesize
758
+ assert_equal 'foobar', str
759
+ end
760
+
761
+ def test_inflate_from_string
762
+ r, w = IO.pipe
763
+ str = Zlib::Deflate.deflate('foobar', 9)
764
+
765
+ ret = IO.inflate(str, w)
766
+ assert_equal 6, ret
683
767
  w.close
684
768
  msg = r.read
685
769
  assert_equal 'foobar', msg
@@ -690,7 +774,7 @@ class IOExtensionsTest < MiniTest::Test
690
774
  dest = Polyphony.pipe
691
775
  now = nil
692
776
 
693
- spin {
777
+ f = spin {
694
778
  now = Time.now
695
779
  IO.gzip(src, dest)
696
780
  dest.close
@@ -698,6 +782,32 @@ class IOExtensionsTest < MiniTest::Test
698
782
 
699
783
  src << IO.read(__FILE__)
700
784
  src.close
785
+ f.await
786
+
787
+ gz = Zlib::GzipReader.new(dest)
788
+ data = gz.read
789
+ assert_equal IO.read(__FILE__), data
790
+ assert_in_range (now-2)..(now+1), gz.mtime
791
+ assert_nil gz.orig_name
792
+ assert_nil gz.comment
793
+ end
794
+
795
+ def test_gzip_to_string
796
+ src = Polyphony.pipe
797
+ dest = Polyphony.pipe
798
+ str = +''
799
+ now = nil
800
+
801
+ f = spin {
802
+ now = Time.now
803
+ IO.gzip(src, str)
804
+ dest << str
805
+ dest.close
806
+ }
807
+
808
+ src << IO.read(__FILE__)
809
+ src.close
810
+ f.await
701
811
 
702
812
  gz = Zlib::GzipReader.new(dest)
703
813
  data = gz.read
@@ -707,6 +817,39 @@ class IOExtensionsTest < MiniTest::Test
707
817
  assert_nil gz.comment
708
818
  end
709
819
 
820
+ def test_gzip_from_string
821
+ str = IO.read(__FILE__)
822
+ dest = Polyphony.pipe
823
+ now = nil
824
+
825
+ IO.gzip(str, dest)
826
+ dest.close
827
+
828
+ gz = Zlib::GzipReader.new(dest)
829
+ data = gz.read
830
+ assert_equal IO.read(__FILE__), data
831
+ end
832
+
833
+ def test_gzip_return_value
834
+ src = Polyphony.pipe
835
+ dest = Polyphony.pipe
836
+ now = nil
837
+ ret = nil
838
+
839
+ f = spin {
840
+ now = Time.now
841
+ ret = IO.gzip(src, dest)
842
+ dest.close
843
+ }
844
+
845
+ src << IO.read(__FILE__)
846
+ src.close
847
+ f.await
848
+
849
+ gzipped = dest.read
850
+ assert_equal gzipped.bytesize, ret
851
+ end
852
+
710
853
  def test_gzip_with_mtime_int
711
854
  src = Polyphony.pipe
712
855
  dest = Polyphony.pipe
@@ -801,19 +944,51 @@ class IOExtensionsTest < MiniTest::Test
801
944
  def test_gunzip
802
945
  src = Polyphony.pipe
803
946
  dest = Polyphony.pipe
947
+ ret = nil
804
948
 
805
- spin {
806
- IO.gunzip(src, dest)
949
+ f = spin {
950
+ ret = IO.gunzip(src, dest)
807
951
  dest.close
808
952
  }
809
953
 
810
954
  gz = Zlib::GzipWriter.new(src, 9)
811
- gz << 'foobar'#IO.read(__FILE__)
955
+ gz << IO.read(__FILE__)
812
956
  gz.close
957
+ f.await
813
958
 
814
959
  data = dest.read
815
- # assert_equal IO.read(__FILE__), data
816
- assert_equal 'foobar', data
960
+ assert_equal IO.read(__FILE__).bytesize, ret
961
+ assert_equal IO.read(__FILE__), data
962
+ end
963
+
964
+ def test_gunzip_to_string
965
+ src = Polyphony.pipe
966
+ str = +''
967
+ ret = nil
968
+
969
+ f = spin {
970
+ ret = IO.gunzip(src, str)
971
+ }
972
+
973
+ gz = Zlib::GzipWriter.new(src, 9)
974
+ gz << IO.read(__FILE__)
975
+ gz.close
976
+ f.await
977
+
978
+ assert_equal IO.read(__FILE__).bytesize, ret
979
+ assert_equal IO.read(__FILE__), str
980
+ end
981
+
982
+ def test_gunzip_from_string
983
+ src_data = 'foobar' * 1000
984
+ str = Zlib.gzip(src_data, level: 9)
985
+ dest = Polyphony.pipe
986
+ ret = IO.gunzip(str, dest)
987
+ dest.close
988
+
989
+ dest_data = dest.read
990
+ assert_equal src_data.bytesize, ret
991
+ assert_equal src_data, dest_data
817
992
  end
818
993
 
819
994
  def test_gunzip_multi
@@ -893,4 +1068,24 @@ class IOExtensionsTest < MiniTest::Test
893
1068
  assert_equal 'foo.bar', dest_info[:orig_name]
894
1069
  assert_equal 'hello!', dest_info[:comment]
895
1070
  end
1071
+
1072
+ def test_deflate_inflate_strings
1073
+ src_data = IO.read(__FILE__)
1074
+ deflated = +''
1075
+ IO.deflate(src_data, deflated)
1076
+ inflated = +''
1077
+ IO.inflate(deflated, inflated)
1078
+
1079
+ assert_equal src_data, inflated
1080
+ end
1081
+
1082
+ def test_gzip_gunzip_strings
1083
+ src_data = IO.read(__FILE__)
1084
+ gzipped = +''
1085
+ IO.gzip(src_data, gzipped)
1086
+ gunzipped = +''
1087
+ IO.gunzip(gzipped, gunzipped)
1088
+
1089
+ assert_equal src_data, gunzipped
1090
+ end
896
1091
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: polyphony
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.87'
4
+ version: '0.89'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sharon Rosner
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-03-17 00:00:00.000000000 Z
11
+ date: 2022-03-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake-compiler
@@ -136,7 +136,7 @@ dependencies:
136
136
  - - "~>"
137
137
  - !ruby/object:Gem::Version
138
138
  version: 1.1.4
139
- description:
139
+ description:
140
140
  email: sharon@noteflakes.com
141
141
  executables: []
142
142
  extensions:
@@ -639,7 +639,7 @@ metadata:
639
639
  documentation_uri: https://digital-fabric.github.io/polyphony/
640
640
  homepage_uri: https://digital-fabric.github.io/polyphony/
641
641
  changelog_uri: https://github.com/digital-fabric/polyphony/blob/master/CHANGELOG.md
642
- post_install_message:
642
+ post_install_message:
643
643
  rdoc_options:
644
644
  - "--title"
645
645
  - polyphony
@@ -658,8 +658,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
658
658
  - !ruby/object:Gem::Version
659
659
  version: '0'
660
660
  requirements: []
661
- rubygems_version: 3.1.6
662
- signing_key:
661
+ rubygems_version: 3.3.3
662
+ signing_key:
663
663
  specification_version: 4
664
664
  summary: Fine grained concurrency for Ruby
665
665
  test_files: []