polyphony 0.87 → 0.89

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 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: []