ori-rb 0.4

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.
Files changed (84) hide show
  1. checksums.yaml +7 -0
  2. data/.rubocop.yml +8 -0
  3. data/.ruby-version +1 -0
  4. data/LICENSE +9 -0
  5. data/README.md +444 -0
  6. data/Rakefile +17 -0
  7. data/docs/images/example_boundary.png +0 -0
  8. data/docs/images/example_boundary_cancellation.png +0 -0
  9. data/docs/images/example_channel.png +0 -0
  10. data/docs/images/example_mutex.png +0 -0
  11. data/docs/images/example_promise.png +0 -0
  12. data/docs/images/example_semaphore.png +0 -0
  13. data/docs/images/example_trace.png +0 -0
  14. data/docs/images/example_trace_tag.png +0 -0
  15. data/lib/ori/channel.rb +148 -0
  16. data/lib/ori/lazy.rb +163 -0
  17. data/lib/ori/mutex.rb +9 -0
  18. data/lib/ori/out/index.html +146 -0
  19. data/lib/ori/out/script.js +3 -0
  20. data/lib/ori/promise.rb +39 -0
  21. data/lib/ori/reentrant_semaphore.rb +68 -0
  22. data/lib/ori/scope.rb +620 -0
  23. data/lib/ori/select.rb +35 -0
  24. data/lib/ori/selectable.rb +9 -0
  25. data/lib/ori/semaphore.rb +49 -0
  26. data/lib/ori/task.rb +78 -0
  27. data/lib/ori/timeout.rb +16 -0
  28. data/lib/ori/tracer.rb +335 -0
  29. data/lib/ori/version.rb +5 -0
  30. data/lib/ori.rb +68 -0
  31. data/mise-tasks/test +15 -0
  32. data/mise.toml +40 -0
  33. data/sorbet/config +8 -0
  34. data/sorbet/rbi/gems/.gitattributes +1 -0
  35. data/sorbet/rbi/gems/ast@2.4.3.rbi +585 -0
  36. data/sorbet/rbi/gems/benchmark@0.4.1.rbi +619 -0
  37. data/sorbet/rbi/gems/date@3.4.1.rbi +75 -0
  38. data/sorbet/rbi/gems/erb@5.1.1.rbi +845 -0
  39. data/sorbet/rbi/gems/erubi@1.13.1.rbi +155 -0
  40. data/sorbet/rbi/gems/io-console@0.8.1.rbi +9 -0
  41. data/sorbet/rbi/gems/json@2.15.1.rbi +2101 -0
  42. data/sorbet/rbi/gems/language_server-protocol@3.17.0.5.rbi +9 -0
  43. data/sorbet/rbi/gems/lint_roller@1.1.0.rbi +240 -0
  44. data/sorbet/rbi/gems/logger@1.7.0.rbi +963 -0
  45. data/sorbet/rbi/gems/minitest@5.26.0.rbi +2234 -0
  46. data/sorbet/rbi/gems/netrc@0.11.0.rbi +159 -0
  47. data/sorbet/rbi/gems/nio4r@2.7.4.rbi +293 -0
  48. data/sorbet/rbi/gems/parallel@1.27.0.rbi +291 -0
  49. data/sorbet/rbi/gems/parser@3.3.9.0.rbi +5535 -0
  50. data/sorbet/rbi/gems/pp@0.6.3.rbi +376 -0
  51. data/sorbet/rbi/gems/prettyprint@0.2.0.rbi +477 -0
  52. data/sorbet/rbi/gems/prism@1.5.2.rbi +42056 -0
  53. data/sorbet/rbi/gems/psych@5.2.6.rbi +2469 -0
  54. data/sorbet/rbi/gems/racc@1.8.1.rbi +160 -0
  55. data/sorbet/rbi/gems/rainbow@3.1.1.rbi +403 -0
  56. data/sorbet/rbi/gems/rake@13.3.0.rbi +3036 -0
  57. data/sorbet/rbi/gems/rbi@0.3.7.rbi +7115 -0
  58. data/sorbet/rbi/gems/rbs@3.9.5.rbi +6978 -0
  59. data/sorbet/rbi/gems/rdoc@6.15.0.rbi +12777 -0
  60. data/sorbet/rbi/gems/regexp_parser@2.11.3.rbi +3845 -0
  61. data/sorbet/rbi/gems/reline@0.6.2.rbi +9 -0
  62. data/sorbet/rbi/gems/rexml@3.4.4.rbi +5285 -0
  63. data/sorbet/rbi/gems/rubocop-ast@1.47.1.rbi +7780 -0
  64. data/sorbet/rbi/gems/rubocop-shopify@2.17.1.rbi +9 -0
  65. data/sorbet/rbi/gems/rubocop-sorbet@0.11.0.rbi +2506 -0
  66. data/sorbet/rbi/gems/rubocop@1.81.1.rbi +63489 -0
  67. data/sorbet/rbi/gems/ruby-progressbar@1.13.0.rbi +1318 -0
  68. data/sorbet/rbi/gems/spoom@1.6.3.rbi +6985 -0
  69. data/sorbet/rbi/gems/stringio@3.1.7.rbi +9 -0
  70. data/sorbet/rbi/gems/tapioca@0.16.11.rbi +3628 -0
  71. data/sorbet/rbi/gems/thor@1.4.0.rbi +4399 -0
  72. data/sorbet/rbi/gems/tsort@0.2.0.rbi +393 -0
  73. data/sorbet/rbi/gems/unicode-display_width@3.2.0.rbi +132 -0
  74. data/sorbet/rbi/gems/unicode-emoji@4.1.0.rbi +251 -0
  75. data/sorbet/rbi/gems/vernier@1.8.1-96ce5c739bfe6a18d2f4393f4219a1bf48674b87.rbi +904 -0
  76. data/sorbet/rbi/gems/yard-sorbet@0.9.0.rbi +435 -0
  77. data/sorbet/rbi/gems/yard@0.9.37.rbi +18379 -0
  78. data/sorbet/rbi/gems/zeitwerk@2.7.3.rbi +1429 -0
  79. data/sorbet/shims/fiber.rbi +21 -0
  80. data/sorbet/shims/io.rbi +8 -0
  81. data/sorbet/shims/random.rbi +9 -0
  82. data/sorbet/shims/rdoc.rbi +3 -0
  83. data/sorbet/tapioca/require.rb +7 -0
  84. metadata +169 -0
data/lib/ori/lazy.rb ADDED
@@ -0,0 +1,163 @@
1
+ # typed: true
2
+
3
+ module Ori
4
+ class Lazy
5
+ def initialize(init_proc)
6
+ @proc = init_proc
7
+ end
8
+
9
+ def internal
10
+ @internal ||= @proc.call
11
+ end
12
+
13
+ def initialized?
14
+ instance_variable_defined?(:@internal)
15
+ end
16
+ end
17
+
18
+ class LazyEnumerable < Lazy
19
+ def each(&block)
20
+ return enum_for(:each) unless block_given?
21
+ return self unless initialized?
22
+
23
+ internal.each(&block)
24
+ end
25
+
26
+ def delete_if(&block)
27
+ return self unless initialized?
28
+
29
+ internal.delete_if(&block)
30
+ end
31
+
32
+ def any?(&block)
33
+ return false unless initialized?
34
+
35
+ internal.any?(&block)
36
+ end
37
+
38
+ def empty?
39
+ return true unless initialized?
40
+
41
+ internal.empty?
42
+ end
43
+ end
44
+
45
+ class LazyArray < LazyEnumerable
46
+ INIT = proc { [] }
47
+ def initialize
48
+ super(INIT)
49
+ end
50
+
51
+ def [](index)
52
+ internal[index] if initialized?
53
+ end
54
+
55
+ def push(value)
56
+ internal.push(value)
57
+ end
58
+
59
+ def []=(index, value)
60
+ internal[index] = value
61
+ end
62
+
63
+ alias_method :<<, :push
64
+
65
+ def size
66
+ return 0 unless initialized?
67
+
68
+ internal.size
69
+ end
70
+
71
+ def shift
72
+ return unless initialized?
73
+
74
+ internal.shift
75
+ end
76
+ end
77
+
78
+ class LazyHash < LazyEnumerable
79
+ INIT = proc { {} }
80
+
81
+ def initialize
82
+ super(INIT)
83
+ end
84
+
85
+ def [](key)
86
+ internal[key] if initialized?
87
+ end
88
+
89
+ def []=(key, value)
90
+ internal[key] = value
91
+ end
92
+
93
+ def delete(key)
94
+ internal.delete(key) if initialized?
95
+ end
96
+
97
+ def key?(key)
98
+ return false unless initialized?
99
+
100
+ internal.key?(key)
101
+ end
102
+
103
+ def fetch(index, default = nil)
104
+ internal[index] || default
105
+ end
106
+
107
+ def reject(&block)
108
+ return self unless initialized?
109
+
110
+ internal.reject(&block)
111
+ end
112
+
113
+ def keys
114
+ return [] unless initialized?
115
+
116
+ internal.keys
117
+ end
118
+
119
+ def values
120
+ return [] unless initialized?
121
+
122
+ internal.values
123
+ end
124
+
125
+ def none?
126
+ return true unless initialized?
127
+
128
+ internal.none?
129
+ end
130
+ end
131
+
132
+ class LazyHashSet < LazyEnumerable
133
+ INIT = proc { Hash.new { |hash, key| hash[key] = Set.new } }
134
+
135
+ def initialize
136
+ super(INIT)
137
+ end
138
+
139
+ def [](key)
140
+ internal[key]
141
+ end
142
+
143
+ def []=(key, value)
144
+ internal[key] = value
145
+ end
146
+
147
+ def none?(&block)
148
+ return true unless initialized?
149
+
150
+ internal.none?(&block)
151
+ end
152
+
153
+ def keys
154
+ return [] unless initialized?
155
+
156
+ internal.keys
157
+ end
158
+
159
+ def delete(key)
160
+ internal.delete(key) if initialized?
161
+ end
162
+ end
163
+ end
data/lib/ori/mutex.rb ADDED
@@ -0,0 +1,9 @@
1
+ # typed: true
2
+
3
+ module Ori
4
+ class Mutex < Semaphore
5
+ def initialize
6
+ super(1)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,146 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <style>
5
+ body {
6
+ font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Open Sans', 'Helvetica Neue', sans-serif;
7
+ }
8
+
9
+ .vis-nesting-group.scope {
10
+ background-color: #e8f6ff !important;
11
+ border: none !important;
12
+ border-bottom: 1px solid #ccc !important;
13
+ }
14
+ .vis-group.scope {
15
+ background-color: #ffffd9;
16
+ }
17
+
18
+ .vis-nested-group.fiber {
19
+ background-color: #ffe8e8 !important;
20
+ border: none !important;
21
+ border-bottom: 1px solid #ccc !important;
22
+ }
23
+
24
+ .vis-item {
25
+ border: none;
26
+ }
27
+
28
+ .vis-item.created, .vis-item.opened {
29
+ background-color: #fff;
30
+ border-color: #ccc;
31
+ }
32
+
33
+ .vis-item.yielded {
34
+ background-color: #fff7ba;
35
+ border-color: #cab200;
36
+ border-style: dashed !important;
37
+ }
38
+
39
+ .vis-item.awaiting {
40
+ background-color: #fff;
41
+ border-color: #ccc;
42
+ }
43
+
44
+ .vis-item.sleeping {
45
+ background-color: #ffd7f9;
46
+ border-color: #f595e6;
47
+ border-style: dashed !important;
48
+ }
49
+
50
+ .vis-item.resuming {
51
+ background-color: #dddcff;
52
+ border-color: #a09dff;
53
+ }
54
+
55
+ .vis-item.completed, .vis-item.closed {
56
+ background-color: #e2ffe2;
57
+ border-color: #91df91;
58
+ }
59
+
60
+ .vis-item.waiting_io {
61
+ background-color: #ffd7f9;
62
+ border-color: #f595e6;
63
+ border-style: dashed !important;
64
+ }
65
+
66
+ .vis-item.error {
67
+ background-color: #ff5858;
68
+ border-color: #e12222;
69
+ color: #fff;
70
+ }
71
+
72
+ .vis-item.cancelled {
73
+ background-color: #450404;
74
+ border-color: #000;
75
+ color: #fff;
76
+ }
77
+
78
+ .vis-item.cancelling {
79
+ background-color: #ff9393;
80
+ border-color: #ff6363;
81
+ color: #fff;
82
+ }
83
+
84
+ .vis-item.tag {
85
+ background-color: #fef49c;
86
+ border-color: #d9cf78;
87
+ font-family: "HanziPen SC";
88
+ color: #6f6a40;
89
+ }
90
+
91
+ .vis-item.resource_wait {
92
+ background-color: #fff7ba;
93
+ border-color: #cab200;
94
+ border-style: dashed !important;
95
+ }
96
+
97
+ .vis-item.memcached_read {
98
+ background-color: #c4f2ef;
99
+ border-color: #84c1bd;
100
+ }
101
+
102
+ .vis-item.memcached_write {
103
+ background-color: #b5efb9;
104
+ border-color: #81c385;
105
+ }
106
+ </style>
107
+ </head>
108
+ <body>
109
+ <div id="visualization"></div>
110
+ <p><pre>cmd+scroll to zoom</pre></p>
111
+ <script type="text/javascript" src="https://unpkg.com/vis-timeline/standalone/umd/vis-timeline-graph2d.min.js"></script>
112
+ <script type="module" src="script.js"></script>
113
+
114
+ <script type="module">
115
+ import { dataset, groups } from "./script.js";
116
+ const container = document.getElementById("visualization");
117
+
118
+ const items = new vis.DataSet(dataset);
119
+ const vis_groups = new vis.DataSet(groups);
120
+ const timeline = new vis.Timeline(container);
121
+
122
+ const min = Math.min(...dataset.map(item => item.start));
123
+ const max = Math.max(...dataset.map(item => item.end)) || Math.max(...dataset.map(item => item.start));
124
+
125
+ timeline.setOptions({
126
+ editable: false,
127
+ start: 0,
128
+ end: max * 1.3,
129
+ min: 0,
130
+ max: max * 1.3,
131
+ align: "left",
132
+ showTooltips: true,
133
+ showMajorLabels: false,
134
+ selectable: false,
135
+ zoomKey: "metaKey",
136
+ tooltip: {
137
+ template: ({data}) => data ? JSON.stringify(data) : "",
138
+ delay: 200,
139
+ },
140
+ order: (a, b) => b.start - a.start
141
+ });
142
+ timeline.setGroups(vis_groups);
143
+ timeline.setItems(items);
144
+ </script>
145
+ </body>
146
+ </html>
@@ -0,0 +1,3 @@
1
+ export const groups = [{"id":"main","content":"Root Scope","value":1,"className":"main-scope","nestedGroups":["scope_0193a84b-d670-7066-83b3-7413095d5d28"],"showNested":true},{"id":"scope_0193a84b-d670-7066-83b3-7413095d5d28","order":"0193a84b-d670-7066-83b3-7413095d5d28","content":"Scope 0193a84b-d670-7066-83b3-7413095d5d28","value":2,"className":"scope","showNested":false,"nestedGroups":["fiber_0193a84b-d670-70a7-a1d1-978f760caca3","fiber_0193a84b-d670-70d4-b26a-e0d21d5496bd","fiber_0193a84b-d670-70f9-9d7d-5a00cc080632"]},{"id":"fiber_0193a84b-d670-70a7-a1d1-978f760caca3","content":"Fiber 0193a84b-d670-70a7-a1d1-978f760caca3","value":3,"className":"fiber","showNested":false},{"id":"fiber_0193a84b-d670-70d4-b26a-e0d21d5496bd","content":"Fiber 0193a84b-d670-70d4-b26a-e0d21d5496bd","value":3,"className":"fiber","showNested":false},{"id":"fiber_0193a84b-d670-70f9-9d7d-5a00cc080632","content":"Fiber 0193a84b-d670-70f9-9d7d-5a00cc080632","value":3,"className":"fiber","showNested":false}];
2
+
3
+ export const dataset = [{"group":"scope_0193a84b-d670-7066-83b3-7413095d5d28","content":"opened","start":"0","className":"opened","data":null},{"group":"scope_0193a84b-d670-7066-83b3-7413095d5d28","content":"awaiting","start":"35","className":"awaiting","data":null},{"group":"scope_0193a84b-d670-7066-83b3-7413095d5d28","content":"awaiting","start":"10501","className":"awaiting","data":null},{"group":"scope_0193a84b-d670-7066-83b3-7413095d5d28","content":"closed","start":"10531","className":"closed","data":null},{"group":"fiber_0193a84b-d670-70a7-a1d1-978f760caca3","content":"created","start":"8","className":"created","data":null},{"group":"fiber_0193a84b-d670-70a7-a1d1-978f760caca3","content":"resuming","start":"10","className":"resuming","data":null},{"group":"fiber_0193a84b-d670-70d4-b26a-e0d21d5496bd","content":"created","start":"16","className":"created","data":null},{"group":"fiber_0193a84b-d670-70d4-b26a-e0d21d5496bd","content":"resuming","start":"16","className":"resuming","data":null},{"group":"fiber_0193a84b-d670-70d4-b26a-e0d21d5496bd","content":"sleeping","start":"21","className":"sleeping","data":0.01},{"group":"fiber_0193a84b-d670-70d4-b26a-e0d21d5496bd","content":"yielded","start":"23","className":"yielded","data":null},{"group":"fiber_0193a84b-d670-70f9-9d7d-5a00cc080632","content":"created","start":"25","className":"created","data":null},{"group":"fiber_0193a84b-d670-70f9-9d7d-5a00cc080632","content":"resuming","start":"25","className":"resuming","data":null},{"group":"fiber_0193a84b-d670-70f9-9d7d-5a00cc080632","content":"yielded","start":"28","className":"yielded","data":null},{"group":"fiber_0193a84b-d670-70a7-a1d1-978f760caca3","content":"completed","start":"33","className":"completed","data":null},{"group":"fiber_0193a84b-d670-70f9-9d7d-5a00cc080632","content":"resuming","start":"43","className":"resuming","data":null},{"group":"fiber_0193a84b-d670-70f9-9d7d-5a00cc080632","content":"yielded","start":"44","className":"yielded","data":null},{"group":"fiber_0193a84b-d670-70d4-b26a-e0d21d5496bd","content":"resuming","start":"10482","className":"resuming","data":null},{"group":"fiber_0193a84b-d670-70d4-b26a-e0d21d5496bd","content":"completed","start":"10497","className":"completed","data":null},{"group":"fiber_0193a84b-d670-70f9-9d7d-5a00cc080632","content":"resuming","start":"10514","className":"resuming","data":null},{"group":"fiber_0193a84b-d670-70f9-9d7d-5a00cc080632","content":"completed","start":"10518","className":"completed","data":null}];
@@ -0,0 +1,39 @@
1
+ # typed: true
2
+
3
+ module Ori
4
+ #: [E]
5
+ class Promise
6
+ include(Ori::Selectable)
7
+
8
+ def initialize
9
+ @resolved = false
10
+ @value = nil
11
+ end
12
+
13
+ #: (E value) -> void
14
+ def resolve(value)
15
+ raise "Promise already resolved" if resolved?
16
+
17
+ @resolved = true
18
+ @value = value
19
+ end
20
+
21
+ #: () -> bool
22
+ def resolved?
23
+ @resolved
24
+ end
25
+
26
+ def deconstruct
27
+ await unless resolved?
28
+ [@value]
29
+ end
30
+
31
+ #: () -> E
32
+ def await
33
+ return @value if resolved?
34
+
35
+ Fiber.yield(self) until resolved?
36
+ @value
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,68 @@
1
+ # typed: true
2
+
3
+ module Ori
4
+ class ReentrantSemaphore
5
+ include(Ori::Selectable)
6
+
7
+ def initialize(num_tickets)
8
+ raise ArgumentError, "Number of tickets must be positive" if num_tickets <= 0
9
+
10
+ @tickets = num_tickets
11
+ @available = num_tickets
12
+ @owners = Hash.new(0) # Track fiber -> acquire count
13
+ end
14
+
15
+ def sync
16
+ acquire
17
+ begin
18
+ yield
19
+ ensure
20
+ release
21
+ end
22
+ end
23
+
24
+ def release
25
+ current = Fiber.current
26
+
27
+ if @owners[current] > 0
28
+ @owners[current] -= 1
29
+ if @owners[current] == 0
30
+ @owners.delete(current)
31
+ @available += 1
32
+ end
33
+ return true
34
+ end
35
+
36
+ raise "Cannot release semaphore - not owned by current fiber"
37
+ end
38
+
39
+ def acquire
40
+ current = Fiber.current
41
+
42
+ # If this fiber already owns the semaphore, increment its count
43
+ if @owners[current] > 0
44
+ @owners[current] += 1
45
+ return true
46
+ end
47
+
48
+ # Otherwise wait for an available ticket
49
+ Fiber.yield(self) until available?
50
+ @available -= 1
51
+ @owners[current] = 1
52
+ true
53
+ end
54
+
55
+ def available?
56
+ @available > 0 || @owners[Fiber.current] > 0
57
+ end
58
+
59
+ def count
60
+ @available
61
+ end
62
+
63
+ def await
64
+ Fiber.yield until available?
65
+ true
66
+ end
67
+ end
68
+ end