git.s-ol.nu alivecoding / master lib / util.moon
master

Tree @master (Download .tar.gz)

util.moon @masterraw · history · blame

import Op, ValueStream, EventStream, Input, val, evt from require 'core.base'

all_same = (list) ->
  for v in *list[2,]
    if v != list[1]
      return false

  list[1]

switch_ = ValueStream.meta
  meta:
    name: 'switch'
    summary: "Switch between multiple inputs."
    examples: { '(switch i v0 [v1 v2…])' }
    description: "
- when `i` is `true`, the first value is reproduced.
- when `i` is `false`, the second value is reproduced.
- when `i` is a `num`, it is [math/floor][]ed and the matching argument
  (indexed starting from 0) is reproduced."

  value: class extends Op
    val_or_evt = (val! / evt!)!
    pattern = (val.num / val.bool) + val_or_evt*0
    setup: (inputs) =>
      { i, values } = pattern\match inputs

      @state = values[1].value.__class == ValueStream

      @out = if @state
        ValueStream values[1]\type!
      else
        EventStream values[1]\type!

      super
        i: Input.hot i
        values: [Input.hot v for v in *values]

    tick: =>
      { :i, :values } = @inputs
      active = switch i!
        when true
          values[1]
        when false
          values[2]
        else
          i = 1 + (math.floor i!) % #values
          values[i]
      if @state
        @out\set active and active!
      else
        if active and active\dirty!
          for event in *active!
            @out\add event

edge = ValueStream.meta
  meta:
    name: 'edge'
    summary: "Convert rising edges to bangs."
    examples: { '(edge bool)' }

  value: class extends Op
    setup: (inputs) =>
      @out or= EventStream 'bang'
      value = val.bool\match inputs
      super value: Input.hot value

    tick: =>
      now = @inputs.value!
      if now and not @state.last
        @out\set true
        @state.last = now

change = ValueStream.meta
  meta:
    name: 'change'
    summary: "Convert value changes to events."
    examples: { '(change val)' }

  value: class extends Op
    setup: (inputs) =>
      value = val!\match inputs
      @out or= EventStream value\type!
      super value: Input.hot value

    tick: =>
      now = @inputs.value!
      if now != @state
        @out\add @inputs.value!
        @state = now

hold = ValueStream.meta
  meta:
    name: 'hold'
    summary: "Convert events to value changes."
    examples: { '(hold evt)' }

  value: class extends Op
    setup: (inputs) =>
      event = evt!\match inputs
      @out or= ValueStream event\type!
      super event: Input.hot event

    tick: =>
      for val in *@inputs.event!
        @out\set val

{
  'switch': switch_
  :edge
  :change
  :hold
}