scenario channel [
run [
1:address:channel <- init-channel 3:literal/capacity
1:address:channel <- write 1:address:channel, 34:literal
2:integer, 1:address:channel <- read 1:address:channel
]
memory-should-contain [
2 <- 34
]
]
container channel [
first-full:integer
first-free:integer
data:address:array:location
]
recipe init-channel [
default-space:address:array:location <- new location:type, 30:literal
result:address:channel <- new channel:type
full:address:integer <- get-address result:address:channel/deref, first-full:offset
full:address:integer/deref <- copy 0:literal
free:address:integer <- get-address result:address:channel/deref, first-free:offset
free:address:integer/deref <- copy 0:literal
capacity:integer <- next-ingredient
capacity:integer <- add capacity:integer, 1:literal
dest:address:address:array:location <- get-address result:address:channel/deref, data:offset
dest:address:address:array:location/deref <- new location:type, capacity:integer
reply result:address:channel
]
recipe write [
default-space:address:array:location <- new location:type, 30:literal
chan:address:channel <- next-ingredient
val:location <- next-ingredient
{
full:boolean <- channel-full? chan:address:channel
break-unless full:boolean
full-address:address:integer <- get-address chan:address:channel/deref, first-full:offset
wait-for-location full-address:address:integer/deref
}
circular-buffer:address:array:location <- get chan:address:channel/deref, data:offset
free:address:integer <- get-address chan:address:channel/deref, first-free:offset
dest:address:location <- index-address circular-buffer:address:array:location/deref, free:address:integer/deref
dest:address:location/deref <- copy val:location
free:address:integer/deref <- add free:address:integer/deref, 1:literal
{
len:integer <- length circular-buffer:address:array:location/deref
at-end?:boolean <- greater-or-equal free:address:integer/deref, len:integer
break-unless at-end?:boolean
free:address:integer/deref <- copy 0:literal
}
reply chan:address:channel/same-as-ingredient:0
]
recipe read [
default-space:address:array:location <- new location:type, 30:literal
chan:address:channel <- next-ingredient
{
empty:boolean <- channel-empty? chan:address:channel
break-unless empty:boolean
free-address:address:integer <- get-address chan:address:channel/deref, first-free:offset
wait-for-location free-address:address:integer/deref
}
full:address:integer <- get-address chan:address:channel/deref, first-full:offset
circular-buffer:address:array:location <- get chan:address:channel/deref, data:offset
result:location <- index circular-buffer:address:array:location/deref, full:address:integer/deref
full:address:integer/deref <- add full:address:integer/deref, 1:literal
{
len:integer <- length circular-buffer:address:array:location/deref
at-end?:boolean <- greater-or-equal full:address:integer/deref, len:integer
break-unless at-end?:boolean
full:address:integer/deref <- copy 0:literal
}
reply result:location, chan:address:channel/same-as-ingredient:0
]
scenario channel-initialization [
run [
1:address:channel <- init-channel 3:literal/capacity
2:integer <- get 1:address:channel/deref, first-full:offset
3:integer <- get 1:address:channel/deref, first-free:offset
]
memory-should-contain [
2 <- 0
3 <- 0
]
]
scenario channel-write-increments-free [
run [
1:address:channel <- init-channel 3:literal/capacity
1:address:channel <- write 1:address:channel, 34:literal
2:integer <- get 1:address:channel/deref, first-full:offset
3:integer <- get 1:address:channel/deref, first-free:offset
]
memory-should-contain [
2 <- 0
3 <- 1
]
]
scenario channel-read-increments-full [
run [
1:address:channel <- init-channel 3:literal/capacity
1:address:channel <- write 1:address:channel, 34:literal
_, 1:address:channel <- read 1:address:channel
2:integer <- get 1:address:channel/deref, first-full:offset
3:integer <- get 1:address:channel/deref, first-free:offset
]
memory-should-contain [
2 <- 1
3 <- 1
]
]
scenario channel-wrap [
run [
1:address:channel <- init-channel 1:literal/capacity
1:address:channel <- write 1:address:channel, 34:literal
_, 1:address:channel <- read 1:address:channel
2:integer <- get 1:address:channel/deref, first-free:offset
3:integer <- get 1:address:channel/deref, first-free:offset
1:address:channel <- write 1:address:channel, 34:literal
4:integer <- get 1:address:channel/deref, first-free:offset
_, 1:address:channel <- read 1:address:channel
5:integer <- get 1:address:channel/deref, first-full:offset
]
memory-should-contain [
2 <- 1
3 <- 1
4 <- 0
5 <- 0
]
]
recipe channel-empty? [
default-space:address:array:location <- new location:type, 30:literal
chan:address:channel <- next-ingredient
full:integer <- get chan:address:channel/deref, first-full:offset
free:integer <- get chan:address:channel/deref, first-free:offset
result:boolean <- equal full:integer, free:integer
reply result:boolean
]
recipe channel-full? [
default-space:address:array:location <- new location:type, 30:literal
chan:address:channel <- next-ingredient
tmp:integer <- get chan:address:channel/deref, first-free:offset
tmp:integer <- add tmp:integer, 1:literal
{
len:integer <- channel-capacity chan:address:channel
at-end?:boolean <- greater-or-equal tmp:integer, len:integer
break-unless at-end?:boolean
tmp:integer <- copy 0:literal
}
full:integer <- get chan:address:channel/deref, first-full:offset
result:boolean <- equal full:integer, tmp:integer
reply result:boolean
]
recipe channel-capacity [
default-space:address:array:location <- new location:type, 30:literal
chan:address:channel <- next-ingredient
q:address:array:location <- get chan:address:channel/deref, data:offset
result:integer <- length q:address:array:location/deref
reply result:integer
]
scenario channel-new-empty-not-full [
run [
1:address:channel <- init-channel 3:literal/capacity
2:integer <- channel-empty? 1:address:channel
3:integer <- channel-full? 1:address:channel
]
memory-should-contain [
2 <- 1
3 <- 0
]
]
scenario channel-write-not-empty [
run [
1:address:channel <- init-channel 3:literal/capacity
1:address:channel <- write 1:address:channel, 34:literal
2:integer <- channel-empty? 1:address:channel
3:integer <- channel-full? 1:address:channel
]
memory-should-contain [
2 <- 0
3 <- 0
]
]
scenario channel-write-full [
run [
1:address:channel <- init-channel 1:literal/capacity
1:address:channel <- write 1:address:channel, 34:literal
2:integer <- channel-empty? 1:address:channel
3:integer <- channel-full? 1:address:channel
]
memory-should-contain [
2 <- 0
3 <- 1
]
]
scenario channel-read-not-full [
run [
1:address:channel <- init-channel 1:literal/capacity
1:address:channel <- write 1:address:channel, 34:literal
_, 1:address:channel <- read 1:address:channel
2:integer <- channel-empty? 1:address:channel
3:integer <- channel-full? 1:address:channel
]
memory-should-contain [
2 <- 1
3 <- 0
]
]