https://github.com/akkartik/mu/blob/master/066stream.mu

     1 # new type to help incrementally scan arrays
     2 container stream:_elem [
     3   index:num
     4   data:&:@:_elem
     5 ]
     6
     7 def new-stream s:&:@:_elem -> result:&:stream:_elem [
     8   local-scope
     9   load-inputs
    10   return-unless s, null
    11   result <- new {(stream _elem): type}
    12   *result <- put *result, index:offset, 0
    13   *result <- put *result, data:offset, s
    14 ]
    15
    16 def rewind in:&:stream:_elem -> in:&:stream:_elem [
    17   local-scope
    18   load-inputs
    19   return-unless in
    20   *in <- put *in, index:offset, 0
    21 ]
    22
    23 def read in:&:stream:_elem -> result:_elem, empty?:bool, in:&:stream:_elem [
    24   local-scope
    25   load-inputs
    26   assert in, [cannot read; stream has no data]
    27   empty? <- copy false
    28   idx:num <- get *in, index:offset
    29   s:&:@:_elem <- get *in, data:offset
    30   len:num <- length *s
    31   at-end?:bool <- greater-or-equal idx len
    32   {
    33     break-unless at-end?
    34     empty-result:&:_elem <- new _elem:type
    35     return *empty-result, true
    36   }
    37   result <- index *s, idx
    38   idx <- add idx, 1
    39   *in <- put *in, index:offset, idx
    40 ]
    41
    42 def peek in:&:stream:_elem -> result:_elem, empty?:bool [
    43   local-scope
    44   load-inputs
    45   assert in, [cannot peek; stream has no data]
    46   empty?:bool <- copy false
    47   idx:num <- get *in, index:offset
    48   s:&:@:_elem <- get *in, data:offset
    49   len:num <- length *s
    50   at-end?:bool <- greater-or-equal idx len
    51   {
    52     break-unless at-end?
    53     empty-result:&:_elem <- new _elem:type
    54     return *empty-result, true
    55   }
    56   result <- index *s, idx
    57 ]
    58
    59 def read-line in:&:stream:char -> result:text, in:&:stream:char [
    60   local-scope
    61   load-inputs
    62   assert in, [cannot read-line; stream has no data]
    63   idx:num <- get *in, index:offset
    64   s:text <- get *in, data:offset
    65   next-idx:num <- find-next s, 10/newline, idx
    66   result <- copy-range s, idx, next-idx
    67   idx <- add next-idx, 1  # skip newline
    68   # write back
    69   *in <- put *in, index:offset, idx
    70 ]
    71
    72 def end-of-stream? in:&:stream:_elem -> result:bool [
    73   local-scope
    74   load-inputs
    75   assert in, [cannot check end-of-stream?; stream has no data]
    76   idx:num <- get *in, index:offset
    77   s:&:@:_elem <- get *in, data:offset
    78   len:num <- length *s
    79   result <- greater-or-equal idx, len
    80 ]