10
10
#include < argon/vm/datatype/error.h>
11
11
#include < argon/vm/datatype/nil.h>
12
12
#include < argon/vm/datatype/pcheck.h>
13
+ #include < argon/vm/datatype/tuple.h>
13
14
14
15
#include < argon/vm/datatype/chan.h>
15
16
@@ -22,20 +23,44 @@ ARGON_FUNCTION(chan_chan, Chan,
22
23
" \n "
23
24
" - KWParameters:\n "
24
25
" - backlog: Set the size of the backlog.\n "
26
+ " - defval: Sets the value to be returned when a read operation is performed on a closed channel."
25
27
" - returns: New Chan object.\n " ,
26
28
nullptr , false , true ) {
27
- IntegerUnderlying backlog;
29
+ ArObject *defval;
30
+
31
+ IntegerUnderlying backlog;
28
32
29
33
if (!KParamLookupInt ((Dict *) kwargs, " backlog" , &backlog, 1 ))
30
34
return nullptr ;
31
35
32
- if (backlog<0 ){
33
- ErrorFormat (kValueError [0 ]," backlog value cannot be negative" );
36
+ if (!KParamLookup ((Dict *) kwargs, " defval" , nullptr , &defval, nullptr , false ))
37
+ return nullptr ;
38
+
39
+ if (backlog < 0 ) {
40
+ ErrorFormat (kValueError [0 ], " backlog value cannot be negative" );
34
41
35
42
return nullptr ;
36
43
}
37
44
38
- return (ArObject *) ChanNew (backlog);
45
+ return (ArObject *) ChanNew (defval, backlog);
46
+ }
47
+
48
+ ARGON_METHOD (chan_close, close,
49
+ " Close this channel.\n "
50
+ " \n "
51
+ " The sender should be the only one to close the channel; multiple closures of a channel are considered a non-op.\n "
52
+ " \n " ,
53
+ nullptr , false , false ) {
54
+ auto self = (Chan *) _self;
55
+
56
+ std::unique_lock _ (self->lock );
57
+
58
+ self->close = true ;
59
+
60
+ self->r_queue .NotifyAll ();
61
+ self->w_queue .NotifyAll ();
62
+
63
+ return (ArObject *) IncRef (Nil);
39
64
}
40
65
41
66
ARGON_METHOD (chan_flush, flush,
@@ -58,10 +83,48 @@ ARGON_METHOD(chan_flush, flush,
58
83
return (ArObject *) IncRef (Nil);
59
84
}
60
85
86
+ ARGON_METHOD (chan_isclosed, isclosed,
87
+ " Test if this channel is closed.\n "
88
+ " \n "
89
+ " - Returns: True if channel is closed, false otherwise.\n " ,
90
+ nullptr , false , false ) {
91
+ auto self = (Chan *) _self;
92
+ return (ArObject *) BoolToArBool (self->close );
93
+ }
94
+
95
+ ARGON_METHOD (chan_read, read,
96
+ " Read data from channel.\n "
97
+ " \n "
98
+ " - Returns: Tuple containing the value and a state indicating whether the value is reliable or not. If the state is false, "
99
+ " the channel is closed, and the read value is invalid." ,
100
+ nullptr , false , false ) {
101
+ auto self = (Chan *) _self;
102
+
103
+ ArObject *value;
104
+ Tuple *ret;
105
+
106
+ std::unique_lock _ (self->lock );
107
+
108
+ if (self->close && self->count == 0 )
109
+ return (ArObject *) TupleNew (" ob" , self->defval , false );
110
+
111
+ if (!ChanRead (self, &value))
112
+ return nullptr ;
113
+
114
+ ret = TupleNew (" ob" , value, true );
115
+
116
+ Release (value);
117
+
118
+ return (ArObject *) ret;
119
+ }
120
+
61
121
const FunctionDef chan_methods[] = {
62
122
chan_chan,
63
123
124
+ chan_close,
64
125
chan_flush,
126
+ chan_isclosed,
127
+ chan_read,
65
128
ARGON_METHOD_SENTINEL
66
129
};
67
130
@@ -82,7 +145,8 @@ ArObject *chan_compare(const ArObject *self, const ArObject *other, CompareMode
82
145
}
83
146
84
147
ArObject *chan_repr (const Chan *self) {
85
- return (ArObject *) StringFormat (" <%s -- backlog: %d, count: %d>" , type_chan_->name , self->length , self->count );
148
+ return (ArObject *) StringFormat (" <%s -- backlog: %d, count: %d, closed: %s>" , type_chan_->name , self->length ,
149
+ self->count , self->close ? " true" : " false" );
86
150
}
87
151
88
152
bool chan_dtor (Chan *self) {
@@ -149,6 +213,19 @@ bool argon::vm::datatype::ChanRead(Chan *chan, ArObject **out_value) {
149
213
std::unique_lock _ (chan->lock );
150
214
151
215
if (chan->count == 0 ) {
216
+ if (chan->close ) {
217
+
218
+ if (chan->defval == nullptr ) {
219
+ ErrorFormat (kRuntimeError [0 ], " read from closed channel" );
220
+
221
+ return false ;
222
+ }
223
+
224
+ *out_value = IncRef (chan->defval );
225
+
226
+ return true ;
227
+ }
228
+
152
229
*out_value = nullptr ;
153
230
154
231
chan->r_queue .Wait (FiberStatus::BLOCKED_SUSPENDED);
@@ -170,6 +247,11 @@ bool argon::vm::datatype::ChanRead(Chan *chan, ArObject **out_value) {
170
247
bool argon::vm::datatype::ChanWrite (Chan *chan, ArObject *value) {
171
248
std::unique_lock _ (chan->lock );
172
249
250
+ if (chan->close ) {
251
+ ErrorFormat (kRuntimeError [0 ], " write on closed channel" );
252
+ return false ;
253
+ }
254
+
173
255
if (chan->write == chan->read && chan->count > 0 ) {
174
256
chan->w_queue .Wait (FiberStatus::BLOCKED_SUSPENDED);
175
257
@@ -187,7 +269,7 @@ bool argon::vm::datatype::ChanWrite(Chan *chan, ArObject *value) {
187
269
return true ;
188
270
}
189
271
190
- Chan *argon::vm::datatype::ChanNew (unsigned int backlog) {
272
+ Chan *argon::vm::datatype::ChanNew (ArObject *defval, unsigned int backlog) {
191
273
auto *chan = MakeGCObject<Chan>(type_chan_, false );
192
274
193
275
if (chan != nullptr ) {
@@ -202,11 +284,15 @@ Chan *argon::vm::datatype::ChanNew(unsigned int backlog) {
202
284
new (&chan->r_queue )sync ::NotifyQueue ();
203
285
new (&chan->w_queue )sync ::NotifyQueue ();
204
286
287
+ chan->defval = IncRef (defval);
288
+
205
289
chan->read = 0 ;
206
290
chan->write = 0 ;
207
291
208
292
chan->count = 0 ;
209
293
chan->length = backlog;
294
+
295
+ chan->close = false ;
210
296
}
211
297
212
298
return chan;
0 commit comments