# API Reference

## Types

### Map

    type Map<Key, Value> = {[Key]: Value}

A table with keys of type _Key_ and values of type _Value_

### Set

    type Set<Key> = {[Key]: boolean}

A table with keys of a fixed type _Key_ and a boolean value representing membership of the set (default is false)

### Table

    type Table = {[any]: any}

A table of any type

### Class

    type Class<Object> = {
        new: () -> Object

A class has a constructor returning an instance of _Object_ type

### Handlers

Some functions such as filter will require handlers. There will be a `Key` and `Value` type to denote whether the key or value argument is passed first, but they are both `any` type unless otherwise specified.

### AnyFunction

    type AnyFunction = (...any) -> any

Represents a function which takes any arguments and returns any value

## Tables

These utilities operate on Tables of any kind.

### all

Tables

    type AllHandler = (Value, Key) -> boolean

    all(input: types.Table, handler: AllHandler?): boolean

Iterates through all elements of the _input_ Table.

Calls the _handler_ for each entry and returns `false` if the handler returns falsy for any element which it is called with. Otherwise, all elements were truthy so return `true`.

If the handler is not provided, use the truthiness of the values in the table.

**Examples**

    -- These are the only falsy values in Lua
    Dash.all({nil, false}) --> false

    Dash.all({true, 0, "0"}) --> true

    -- Do all words start with 'ro'?
    Dash.all(
        {"roblox", "roact", "rodux"},
        function(word) return Dash.startsWith(word, "ro")
        end
    )
    Output: true

### collect

Tables

    type CollectHandler = (Key, Value) -> (any, any)?

    collect(input: Types.Table, handler: CollectHandler): Types.Map<any, any>

Collect returns a new Table derived from _input_ by iterating through its pairs and calling the handler on each `(key, value)` tuple.

The handler should return a new `(newKey, value)` tuple to be inserted into the returned Table, or `nil` if no value should be added.

**Example**

    -- Invert keys and values of a table
    Dash.collect({a = "1", b = "2", c = 3}, function(key, value)
        return value, key
    end)

    Output: {
        [3] = "c"
        ["1"] = "a",
        ["2"] = "b",

### collectArray

Tables

    type CollectHandler<Key, Value, NewValue> = (key: Key, value: Value) -> NewValue?

    collectArray<Key, Value, NewValue>(input: { [Key]: Value }, handler: CollectHandler<Key, Value, NewValue>): { NewValue }

Collect returns a new array derived from _input_ by iterating through its pairs and calling the handler on each `(key, value)` tuple.

The handler should return a new value to be pushed onto the end of the result array, or `nil` if no value should be added.

**Example**

    -- Double all elements, ignoring results that are multiples of three
    Dash.collectArray({1, 2, 3, 4, 5, 6}, function(key, value)
        local newValue = value * 2
        return if newValue % 3 == 0 then nil else newValue
    end)

    Output: {
    [1] = 2,
    [2] = 4,
    [3] = 8,
    [4] = 10

### collectSet

Tables

    type CollectHandler<Key, Value, NewValue> = (key: Key, value: Value) -> NewValue?

    collectSet<Key, Value, NewValue>(
        input: { [Key]: Value },
        handler: CollectHandler<Key, Value, NewValue>?
    ): Types.Set<Value | NewValue>

Build a set from the entries of the _input_ Table, calling _handler_ on each entry and using the returned value as an element to add to the set.

If _handler_ is not provided, values of `input` are used as elements.

**Examples**

    -- Convert array to Set
    Dash.collectSet({"toast", "bagel", "donut"})

    Output: {
        ["bagel"] = true,
        ["donut"] = true,
        ["toast"] = true

    -- Create set of first letters of each word
    Dash.collectSet({"toast", "bagel", "donut", "bread"}, function(key, value)
        return value:sub(1, 1)
    end)

    Output: {
        ["b"] = true,
        ["d"] = true,
        ["t"] = true

### copy

Tables

    copy(input: Types.Table): Types.Table

Returns a shallow copy of the _input_ Table.

**Example**

    Dash.copy({a = 1, b = 3})

    Output: {
        ["a"] = 1,
        ["b"] = 3

### count

Tables

    type CountHandler<Key, Value> = (Value, Key) -> boolean

    count<Key, Value>(input: { [Key]: Value }, handler: CountHandler<Key, Value>?): number

If no _handler_ is provided, return the number of elements in the _input_ Table.

If the _handler_ is provided, increase the count for each element for which the handler returns true on the `(value, key)` pair.

**Examples**

    Dash.count({1, 2, 3, 4, 5}) --> 5

    -- Count the number of ids that start with 1
    Dash.count(
        {[12] = true, [24] = true, [153] = true, [199] = true},
        function(value, id) return tostring(id):sub(1, 1) == "1"
        end)

    Output: 3

    -- Count the number of numbers divisible by 5
    Dash.count(
        {1, 1, 2, 3, 5, 8, 13, 21, 34, 55},
        function(num) return num % 5 == 0
        end)

    Output: 2

### filter

Tables

    type FilterHandler<Key, Value> = (Value, Key) -> boolean

    filter<Key, Value>(input: { [Key]: Value }, handler: FilterHandler<Key, Value>): { Value }

Filter the _input_ Table by calling the handler on each `(value, key)` tuple.

For an array input, the order of elements is preserved in the output.

The handler should return truthy to preserve the value in the resulting Table.

**Example**

    -- Take only the elements whose values begin with "r"
    Dash.filter(
        {place = "roblox", packages = "rotriever", ide = "studio"},
        function(word) return Dash.startsWith(word, "r")
        end)

    Output: {
        [1] = "roblox",
        [2] = "rotriever"

### find

Tables

    type FindHandler<Key, Value> = (Value, Key) -> boolean

    find<Key, Value>(input: { [Key]: Value }, handler: FindHandler<Key, Value>): Value?

Returns an element in the _input_ Table that the handler returns `true` for, when passed the `(value, key)` entry.

Returns nil if no entries satisfy the condition.

For an array, this first matching element is returned. For a Map, an arbitrary matching element is returned if it exists.

**Examples**

    -- Check if there's the "ExtraSettings" key and get the value of that key if so
    Dash.find(
        {Id = 145, IsReady = false, ExtraSettings = {AutoReady = true}},
        function(value, key) return key == "ExtraSettings"
        end
    )

    Output: {
        ["AutoReady"] = true

    Dash.find({Id = 145, IsReady = false},
        function(value, key) return key == "ExtraSettings"
        end
    )
    Output: nil

### forEach

Tables

    type ForEachHandler<Key, Value> = (Value, Key) -> ()

    forEach<Key, Value>(input: { [Key]: Value }, handler: ForEachHandler<Key, Value>)

Iterates through the elements of the _input_ Table.

If the table is an array, it iterates in order 1..n.

If the table is a Map, the keys are visited in an arbitrary order.

Calls the _handler_ for each entry.

**Example**

    -- Print all values of a table
    Dash.forEach({"Item 1", "Item 2", "Item 3" }, function(value) print(value)
    end)

    Output: Item 1
    Item 2
    Item 3

    -- Print all values joined with keys
    Dash.forEach({ a = "Item", b = "Item", c = "Item" }, function(value: string, key: string) print(value .. key)
    end)

    Output: Item a
    Item b
    Item c

### frequencies

Tables

    type FrequenciesHandler<Key, Value, NewKey> = (Value, Key) -> NewKey

    frequencies<Key, Value, NewKey>(
        input: { [Key]: Value },
        handler: FrequenciesHandler<Key, Value, NewKey>?
    ): { [NewKey | Value]: number }

If no handler is provided, returns a Map with keys as unique values of the _input_ Table and values as the count of each value.

If a handler is provided, returns a Map with keys as unique elements given by the _handler_ and values as the count of each mapped key.

**Examples**

    Dash.frequencies({"Red", "Black", "Orange", "Red"})

    Output:{
        ["Black"] = 1,
        ["Orange"] = 1,
        ["Red"] = 2

    -- Count colors by a simple definition of neutral and non-neutral
    function toNeutral(color)
        return if Dash.includes({"Black", "Gray", "White"}, color)
            then "Neutral"
            else "Non-neutral"
    end
    Dash.frequencies(
        {"Black", "Orange", "Blue", "Gray", "White"},
        function(color) return toNeutral(color)
        end)

    Output: {
        ["Neutral"] = 3,
        ["Non-neutral"] = 2

### groupBy

Tables

    type GroupByHandler<Key, Value, GroupKey> = (Value, Key) -> GroupKey

    groupBy<Key, Value, GroupKey>(
        input: { [Key]: Value },
        getKey: GroupByHandler<Key, Value, GroupKey> | GroupKey
    ): { [GroupKey]: { Value } }

Groups values in the _input_ Table by their _getKey_ value.

Each value of the result Table is an array of values from the _input_ Table which were assigned the corresponding key.

If _getKey_ is a function, it is called with each `(value, key)` entry and uses the return value as the corresponding key to insert at in the result Table. Otherwise, the _getKey_ value is used directly as the key itself.

**Example**

    local output = groupBy({
        bike = {
            name = "bike",
            color = "blue"
        },
        car = {
            name = "car",
            color = "red"
        },
        van = {
            name = "van",
            color = "white"
        },
        ghost = {
            name = "ghost"
    }, "color")
    Output: {
        blue = {
                color = "blue",
                name = "bike"
        },
        red = {
                color = "red",
                name = "car"
        },
        white = {
                color = "white",
                name = "van"

### includes

Tables

    includes(source: Types.Table, value: any): boolean

Returns _true_ if the _item_ exists as a value in the _source_ Table.

**Example**

    -- Does the table include 100?
    Dash.includes({1, 10, 100, 1000}, 100)

    Output: true

**See**

For a stronger version of `Dash.includes`, use Dash.some.

### keyBy

Tables

    type KeyByHandler<Key, Value, NewKey> = (Value, Key) -> NewKey

    keyBy<Key, Value, NewKey>(input: { [Key]: Value }, getKey: KeyByHandler<Key, Value, NewKey> | NewKey): { [NewKey]: Value }

Assigns values in the _input_ Table by their _getKey_ value.

If _getKey_ is a function, it is called with each `(value, key)` entry and uses the return value as the corresponding key to assign to in the result Table. Otherwise, the _getKey_ value is used directly as the key itself.

**Example**

    local output = keyBy({
        bike = {
            name = "bike",
            color = "blue"
        },
        car = {
            name = "car",
            color = "red"
        },
        van = {
            name = "van",
            color = "white"
        },
        ghost = {
            name = "ghost"
    }, "color")

    Output: {
        blue = {
            color = "blue",
            name = "bike"
        },
        red = {
            color = "red",
            name = "car"
        },
        white = {
            color = "white",
            name = "van"

### keys

Tables

    keys<Key, Value>(input: { [Key]: Value }): { Key }

Returns an array of the keys in the _input_ Table.

If the input is an array, ordering is preserved.

If the input is a Map, elements are keys in an arbitrary order.

**Example**:

    Dash.keys({
        Color = "Purple",
        Type = "Fruit",
        Shape = "Round"
    })

    Output: {
        [1] = "Color",
        [2] = "Type",
        [3] = "Shape"

### map

Tables

    type MapHandler<Key, Value, NewValue> = (Value, Key) -> NewValue

    map<Key, Value, NewValue>(input: { [Key]: Value }, handler: MapHandler<Key, Value, NewValue>): { [Key]: NewValue }

Iterates through the elements of the _input_ Table.

For an array input, the elements are visited in order 1..n.

For a Map input, the elements are visited in an arbitrary order.

Calls the _handler_ for each entry and constructs a new Table using the same keys but replacing the values with new ones returned from the handler.

Values returned by _handler_ must be defined.

**Examples**

    -- Map characters to their ASCII
    Dash.map({"a", "b", "c"}, function(char) return string.byte(char)
    end)

    Output: {
        [1] = 97,
        [2] = 98,
        [3] = 99

    -- Map values using their keys
    Dash.map({ a = 1, b = 2, c = 3 }, function(value: number, key: string) return string.byte(key) + value
    end)

    Output: {
        a = 98,
        b = 100,
        c = 102

**See**

  * Dash.collectArray if you want to return nil values.

### mapOne

Tables

    type MapHandler<Key, Value, NewValue> = (Value, Key) -> NewValue?

    mapOne<Key, Value, NewValue>(input: { [Key]: Value }, handler: MapHandler<Key, Value, NewValue>?): NewValue?

Iterates through the elements of the _input_ Table in no particular order.

Calls the _handler_ for each entry and returns the first non-nil value returned by the _handler_. If all returned from the _handler_ values are `nil`, `nil` is returned.

If _handler_ is `nil`, the first value visited is returned.

**Example**

    -- Get any message that's not hidden and return its id.
    Dash.mapOne({
        {Id = 1, IsHidden = true},
        {Id = 3, IsHidden = false},
        {Id = 2, IsHidden = false},
    }, function(message)
        return if message.IsHidden then nil else message.Id
    end)

    Output: 3

### max

Tables

    type MaxComparator = (any, any) -> boolean
    type MaxHandler = (Value, Key) -> any

    max(input: Types.Table, handler: MaxHandler?, comparator: MaxComparator): any

Returns the maximum value in the _input_ Table. By default, this returns the greatest value in the table as defined by the `>` operator.

If a _handler_ is provided, elements will first be transformed by `handler(value, key)` before being used for comparison.

Elements will be compared using the _comparator_ if it is provided. The comparator should take two elements and return `true` if the first one is greater than the second one, and `false` otherwise.

If the provided _input_ has no elements, return `nil`.

**Examples**

    Dash.max({1, 2, 3}) --> 3

    Dash.max({"1", "2", "10"}) --> "2"

    Dash.max({1, 2, 3}, function(num) return -num
    end) --> 1

    Dash.max(
        {"blue", "red", "orange"},
        nil,
        function(word1, word2) return word1:len() > word2:len()
        end
    ) --> "orange"

### min

Table

    type MinComparator = (any, any) -> boolean
    type MinHandler = (Value, Key) -> any

    min(input: Types.Table, handler: MinHandler?, comparator: MinComparator): any

Returns the minimum value in the _input_ Table. By default, this returns the least value in the table as defined by the `<` operator.

If a _handler_ is provided, elements will first be transformed by `handler(value, key)` before being used for comparison.

Elements will be compared using the _comparator_ if it is provided. The comparator should take two elements and return `true` if the first one is less than the second one, and `false` otherwise.

If the provided _input_ has no elements, return `nil`.

**Examples**

    Dash.min({1, 2, 3}) --> 1

    Dash.min({"2", "20", "10"}) --> "10"

    Dash.min({3, 2, 1}, function(num) return -num
    end) --> 3

    Dash.min(
        {"blue", "red", "orange"},
        nil,
        function(word1, word2) return word1:len() < word2:len()
        end
    ) --> "red"

### omit

Tables

    omit<Key, Value>(input: { [Key]: Value }, keys: { Key }): { [Key]: Value }

Return a new Table made from entries in the _input_ Table whose key is not in the _keys_ array.

If the input is an array, ordering is preserved.

If the input is a Map, elements are returned in an arbitrary order.

**Example**

    -- Remove the ShouldShow key/value pair from the table
    Dash.omit({
        ShouldShow = true,
        Text = "Hello World!",
        Title = "Greetings!",
    }, {"ShouldShow"})

    Output: {
        ["Text"] = "Hello World!",
        ["Title"] = "Greetings!"

### pick

Tables

    type PickHandler<Key, Value> = (Value, Key) -> boolean

    pick<Key, Value>(input: { [Key]: Value }, handler: PickHandler<Key, Value>): { [Key]: Value }

Pick entries in the _input_ Table which should remain in the output by calling the handler on each `(child, index)` tuple.

The handler should return truthy to preserve the value in the resulting Table.

**Examples**

    Dash.pick(
        {10, 20, 30, 40, 50, 60},
        function(value, _) return value % 20 == 0
        end
    )

    Output: {
        [2] = 20,
        [4] = 40,
        [6] = 60

### pipe

    pipe<Args...>(f: (Args...) -> any, ...: (...any) -> any): (Args...) -> any

Creates a function that returns the result of passing a value through a pipeline of functions. Each function in the pipeline receives the result of the previous function. Functions are executed from left to right.

**Example**

    local function addOne(n)
        return n + 1
    end

    local function double(n)
        return n * 2
    end

    local addThenDouble = pipe(addOne, double)
    print(addThenDouble(2)) -- prints 6 ((2 + 1) * 2)

### reduce

Tables

    type ReduceHandler<Key, Value, Accumulator> = (Accumulator, Value, Key) -> Accumulator

    reduce<Key, Value, Accumulator>(
        input: { [Key]: Value },
        handler: ReduceHandler<Key, Value, Accumulator>,
        initial: Accumulator
    ): Accumulator

Iterate through the elements of the _input_ Table, preserving order if it is an array.

Call the _handler_ for each element, passing the return of the previous call as the first argument.

The _initial_ value is passed into the first call, and the final value returned by the function.

**Examples**

    -- Count occurrences of each element in array and output a table of counts
    -- See Dash.frequencies
    Dash.reduce(
        {"Red", "Black", "Red", "Red", "Black"},
        function(acc, color)
            if acc[color] == nil then
                acc[color] = 1
            else
                acc[color] += 1
            end
            return acc
        end, {}
    )

    Output: {
        ["Black"] = 2,
        ["Red"] = 3

    -- Sum up elements, doubling even indices and halving odd indices
    -- Expected: 0.5 + 4 + 1.5 + 8 + 2.5 = 16.5
    Dash.reduce(
        {1, 2, 3, 4, 5},
        function(acc, num, index)
            return acc + if index % 2 == 0 then num * 2 else num / 2
        end, 0
    )
    Output: 16.5

### shallowEqual

Tables

    shallowEqual(left: any, right: any): boolean

Returns `true` if the _left_ and _right_ values are equal (by the equality operator) or the inputs are tables, and all their keys are equal.

**Examples**

    Dash.shallowEqual({
        A = 1,
        B = 2
    }, {
        A = 1,
        B = 2,
    })

    Output: true

    Dash.shallowEqual({
        A = 1,
        B = 2,
        C = 3
    }, {
        A = 1,
        B = 2,
        D = 3
    })

    Output: false

### some

Tables

    type SomeHandler<Key, Value> = (Value, Key) -> boolean

    some<Key, Value>(input: { [Key]: Value }, handler: SomeHandler<Key, Value>): boolean

Iterates through the elements of the _input_ Table in no particular order.

Calls the _handler_ for each entry and returns `true` if the handler returns truthy for any element which it is called with.

**Example**

    -- Does there exist a red fruit?
    Dash.some(
            {Type = "Cherry", Color = "Red"},
            {Type = "Strawberry", Color = "Red"},
            {Type = "Blueberry", Color = "Blue"}
        },
        function(fruit) return fruit.Color == "Red"
        end
    )

    Output: true

### union

Tables

    union(map1: T, map2: U): T & U

Returns a new Table by merging all keys in the two Tables in left-to-right order.

The `Dash.None` symbol can be used to remove existing elements.

**Example**

    union({ a = 1, b = 2 }, { c = 3, d = 4 })

    Output: { a = 1, b = 2, c = 3, d = 4 }

### values

Tables

    values<Key, Value>(input: { [Key]: Value }): { Value }

Returns an array of the values in the _input_ Table.

If the input is an array, ordering is preserved.

If the input is a Map, values are returned in an arbitrary order.

**Example**

    Dash.values({
        Type = "Cherry",
        Color = "Red",
        Price = "Expensive",
        EnjoymentLevel = "High"
    })

    Output: {
        [1] = "Red",
        [2] = "Cherry",
        [3] = "High",
        [4] = "Expensive"

## Arrays

These utilities operate on arrays, tables with ordered keys 1..n.

### append

Mutable | Arrays

    append<T>(target: { T }, ...: { T }): { T }

Adds new elements to the _target_ array from subsequent array arguments in left-to-right order.

Arguments which are `nil` or None are skipped.

**Example**

    Dash.append({1, 2}, {3, 4}, {5})

    Output: {
        [1] = 1,
        [2] = 2,
        [3] = 3,
        [4] = 4,
        [5] = 5

**See**

  * Dash.joinArrays for an immutable alternative

### findIndex

Arrays

    type FindHandler<Value> = (Value, number) -> boolean

    findIndex<Value>(input: { Value }, handler: FindHandler<Value>): number?

Returns the index of the first element in the _input_ array that the handler returns `true` for, when passed the `(value, key)` entry.

Returns nil if no entries satisfy the condition.

**Examples**

    -- Find index of "Clementine" fruit if it exists in the array
    Dash.findIndex(
        {"Apple", "Banana", "Clementine"},
        function(fruit) return fruit == "Clementine"
        end
    )

    Output: 3

    Dash.findIndex(
        {"Apple", "Banana"},
        function(fruit) return fruit == "Clementine"
        end
    )

    Output: nil

### flat

Arrays

    flat(input: { any }): { any }

Flattens the input array by a single level. Outputs a new array of elements merged from the _input_ array arguments in left-to-right order.

**Example**

    -- Flatten a partition of numbers in the range 1-5
    Dash.flat({
        {1, 2, 3},
        {4, 5}
    })

    Output:  {
        [1] = 1,
        [2] = 2,
        [3] = 3,
        [4] = 4,
        [5] = 5

### joinArrays

Arrays

    joinArray(...: {}?): { [any]: any }

Output a new array table from merging all the given array tables in left-to-right order.

**Example**

    Dash.join(
        { "Hello World!", "Sky Blue" },
        { "Greetings!", "Indigo"}
    )

    Output: { "Hello World!", "Sky Blue", "Greetings!", "Indigo" }

**See**

  * Dash.append for a mutable alternative

### last

Arrays

    type FindHandler<Value> = (Value, number) -> boolean

    last<Value>(input: { Value }, handler: FindHandler<Value>?): Value?

Returns the last element in the _input_ array that the handler returns `true` for, when passed the `(value, key)` entry.

Returns nil if no entries satisfy the condition.

If handler is not defined, the function simply returns the last element of the array.

**Examples**

    Dash.last({3, 2, 1})

    Output: 1

    -- Get last odd number
    Dash.last({4, 3, 2}, function(num) return num % 2 == 1
    end)

    Output: 3

### mapFirst

Arrays

    type MapHandler<Value, NewValue> = (Value, number) -> NewValue?

    mapFirst<Value, NewValue>(input: { Value }, handler: MapHandler<Value, NewValue>): NewValue?

Iterates through the elements of the _input_ array in order 1..n.

Calls the _handler_ for each entry and returns the first non-nil value returned by the _handler_. If all returned from the _handler_ values are `nil`, `nil` is returned.

**Example**

    -- Get first color that's 6 letters and return its first letter
    Dash.mapFirst(
        {"Red", "Yellow", "Orange", "Blue"},
        function(color)
            return if color:len() == 6 then color:sub(1, 1) else nil
        end
    )

    Output: Y

### mapLast

Arrays

    type MapHandler<Value, NewValue> = (Value, number) -> NewValue?

    mapLast<Value, NewValue>(input: { Value }, handler: MapHandler<Value, NewValue>): NewValue?

Iterates through the elements of the _input_ array in reverse in order n..1.

Calls the _handler_ for each entry and returns the first non-nil value returned by the handler. If all returned from the _handler_ values are `nil`, `nil` is returned.

**Example**

    -- Get last color that's 6 letters and return its first letter
    Dash.mapLast(
        {"Red", "Yellow", "Orange", "Blue"},
        function(color)
            return if color:len() == 6 then color:sub(1, 1) else nil
        end
    )

    Output: O

### product

Arrays

    product(input: { number }): number

Multiplies together all the numbers in the _input_ array.

If the _input_ has no elements, return `1`.

**Example**

    Dash.product({3, 3, 2}) --> 18

### reverse

Arrays

    reverse<T>(input: { T }): { T }

Reverse the order of the elements in the _input_ array.

**Example**

    Dash.reverse({3, 2, 1})

    Output: {
        [1] = 1,
        [2] = 2,
        [3] = 3

### slice

Arrays

    slice<T>(input: { T }, left: number?, right: number?): { T }

Return a portion of the _input_ array starting with the element at the _left_ index and ending with the element at the _right_ index (i.e. an inclusive range)

If _left_ is not defined, it defaults to 1. If _right_ is not defined, it defaults to the length of the array (i.e. the last element)

If _left_ is `-n`, the slice starts with the element `n` places from the last one. If _right_ is `-n`, the slice ends with the element `n` places from the last one.

An empty array is returned if the slice has no or negative length.

**Examples**

    Dash.slice({1, 2, 3, 4, 5}, 2, 4)

    Output: {
        [1] = 2,
        [2] = 3,
        [3] = 4

    Dash.slice({1, 2, 3, 4, 5}, 3)

    Output: {
        [1] = 3,
        [2] = 4,
        [3] = 5

    Dash.slice({1, 2, 3, 4, 5}, nil, -1)

    Output: {
        [1] = 1,
        [2] = 2,
        [3] = 3,
        [4] = 4

### sum

Arrays

    sum(input: { number }): number

Adds together all the numbers in the _input_ array.

If the input array has no elements, return `0`.

**Example**

    Dash.sum({3, 2, 1}) --> 6

## Maps

These utilities operate on Maps, tables with arbitrary keys.

### assign

Mutable | Maps

    assign<Key, Value>(target: Types.Map<Key, Value>, ...: Types.Map<Key, Value>): Types.Map<Key, Value>

Adds new values to _target_ from subsequent Table arguments in left-to-right order.

**Examples**

    local characters = {
        Frodo = {
            name = "Frodo Baggins",
            team = "blue"
        },
        Boromir = {
            score = 5
    local otherCharacters = {
        Frodo = {
            team = "red",
            score = 10
        },
        Bilbo = {
            team = "yellow",
        },
        Boromir = {
            score = {1, 2, 3}
    local result = assign(characters, otherCharacters)
    print(result) --[[
        Frodo = {
            team = "red",
            score = 10
        },
        Bilbo = {
            team = "yellow"
        },
        Boromir = {
            score = {1, 2, 3}

**See**

  * Dash.join for an immutable alternative

### freeze

Maps

    freeze(objectName: string, object: Types.Table, throwIfMissing: boolean?): Types.Table

Returns a new read-only view of _object_ which prevents any values from being changed.

**Parameters**

Name | Description
`name` | The name of the object for improved error message readability.
`throwIfMissing` | If `true` then access to a missing key will also throw.

**Notes**

Unfortunately you cannot iterate using `pairs` or `ipairs` on frozen objects because Luau doesn't support defining these custom iterators in metatables.

**Example**

    local drink = freeze("Ice Cream", {
        flavor = "mint",
        topping = "sprinkles"
    }, true)
    print(drink.flavor) --> "mint"
    drink.flavor = "vanilla"
    --!> ReadonlyKey: Attempt to write to readonly key "flavor" (a string) of frozen object "Ice Cream"
    print(drink.syrup) --> nil
    --!> MissingKey: Attempt to read missing key "syrup" (a string) of frozen object "Ice Cream"

### get

Tables

    get<T>(object: { [any]: any }, path: { any }, defaultValue: T?): T?

Gets the value at path of object. If the resolved value is nil, the defaultValue is returned in its place.

The path should be an array of keys (e.g. `{ "a", "b", "c" }`, `{ "test", "test.test", 0 }`).

**Examples**

    local object = {
        a = {
            b = {
                c = 3
    Dash.get(object, { "a", "b", "c" }) --> 3
    Dash.get(object, { "x", "y", "z" }, "default") --> "default"

    -- Array indexing
    local object = {
        items = {
            { name = "first" },
            { name = "second" }
    Dash.get(object, { "items", 1, "name" }) --> "first"

    -- Keys with dots
    local object = {
        test = {
            ["test.test"] = {
                [0] = "value"
    Dash.get(object, { "test", "test.test", 0 }) --> "value"

**See**

  * Dash.getOrSet \- for getting a value with a default generator function

### getOrSet

Maps

    type GetValueHandler<Key, Value> = ({ [Key]: Value }, Key) -> Value

    getOrSet<Key, Value>(input: { [Key]: Value }, key: Key, getValue: GetValueHandler<Key, Value>): Value

Returns a value of the _input_ Table at the _key_ provided. If the key is missing, the value is acquired from the _getValue_ handler, added to the _input_ Table and returned.

**Examples**

    Dash.getOrSet(
        {Item = "Gummy Bear", Color = "Lime"},
        "Color",
        function() return "Yellow"
        end
    )

    Output: Lime

    Dash.getOrSet(
        {Item = "Gummy Bear"},
        "Color",
        function() return "Yellow"
        end
    )

    Output: Yellow

### join

Maps

    join<Key, Value>(...: Types.Map<Key, Value>): Types.Map<Key, Value>

Output a new Map from merging all the keys in the Map arguments in left-to-right order.

**Example**

    Dash.join(
        {Text = "Hello World!", Color = "Sky Blue"},
        {Title = "Greetings!", Color = "Indigo"}
    )

    Output: {
        ["Color"] = "Indigo",
        ["Text"] = "Hello World!",
        ["Title"] = "Greetings!"

**See**

  * Dash.assign for a mutable alternative

### joinDeep

Maps

    joinDeep(source: Types.Map<any, any>, delta: Types.Map<any, any>): Types.Map<any, any>

Creates a shallow clone of the _source_ Map and copies the values from the _delta_ Map by key, like the join utility.

However, if any of the values are tables themselves, the joinDeep function is called recursively to produce a new table at the specified key.

The purpose of this function is to merge nested immutable data using as few table creation operations as possible, making it appropriate for updating state in a reducer.

**Usage**

  * The None symbol can be used to remove an existing value.

**Example**

    local source = {
        name = "car",
        lights = {
            front = 2,
            back = 2,
            indicators = {
                color = "orange"
            },
            brake = {
                color = "red"
        },
        tyres = 4
    local delta = {
        name = "bike",
        lights = {
            front = 3,
            indicators = {
                rate = 20
        },
        tyres = None
    local output = joinDeep(source, delta)
    Output: {
        lights = {
            back = 2,
            brake = {
                color = "red"
            },
            front = 3,
            indicators = {
                color = "orange",
                rate = 20
        },
        name = "bike"

### mapNotNil

Maps

    type MapHandler<Key, Value> = (Value, Key) -> boolean

    mapNotNil(input: {}, handler: MapHandler<any, any, any>): Types.Table

Returns a new table by applying the _handler_ to each element of _input_.

If a nil value is returned from the handler, the associated key is _not_ added to the new table.

It's useful when you already have a function returning nil for values you do not want to include. Otherwise, it's better to use Dash.collect and Dash.collectArray

**Example**

    local output = mapNotNil({ a = 10, b = 20, c = 30, d = 50 }, function(value: number, key: string)
        if key == "c" then
            return nil
        end
        return key .. "=" .. value
    end)

    Output: {
        a = "a=10",
        b = "b=20",
        d = "d=50",

**See**

  * Dash.collect \- for mapping and collecting values you need into a new table
  * Dash.collectArray \- for mapping and collecting values you need into a new array

## Strings

These utilities are helpful for working with strings.

### endsWith

Strings

    endsWith(input: string, suffix: string): boolean

Checks if _input_ ends with the string _suffix_.

**Examples**

    endsWith("Fun Roblox Games", "Games") --> true

    endsWith("Bad Roblox Memes", "Games") --> false

### isLowercase

Strings

    isLowercase(input: string): boolean

Returns `true` if the first character of _input_ is a lower-case character.

Throws if the _input_ is not a string or it is the empty string.

Our current version of Lua unfortunately does not support upper or lower-case detection outside the English alphabet. This function has been implemented to return the expected result once this has been corrected.

**Examples**

    Dash.isLowercase("abcdef") --> true

    Dash.isLowercase("Title") --> false

### isUppercase

Strings

    isUppercase(input: string): boolean

Returns `true` if the first character of _input_ is an upper-case character.

Throws if the _input_ is not a string or it is the empty string.

Our current version of Lua unfortunately does not support upper or lower-case detection outside the English alphabet. This function has been implemented to return the expected result once this has been corrected.

**Examples**

    Dash.isUppercase("ABCDEF") --> true

    Dash.isUppercase("rObLoX") --> false

### leftPad

Strings

    leftPad(input: string, length: number, prefix: string?): string

Makes a string of `length` from `input` by repeating characters from `prefix` at the start of the string.

**Params**

  * `prefix` \- default = `""`

**Examples**

    leftPad("toast", 6) --> " toast"

    leftPad("2", 2, "0") --> "02"

    leftPad("toast", 10, ":)") --> ":):):toast"

### rightPad

Strings

    rightPad(input: string, length: number, suffix: string?): string

Makes a string of `length` from `input` by repeating characters from `suffix` at the end of the string.

By default, suffix is `" "`.

**Examples**

    rightPad("toast", 6) --> "toast "

    rightPad("2", 2, "!") --> "2!"

    rightPad("toast", 10, ":)") --> "toast:):):"

### splitOn

Strings

    splitOn(input: string, pattern: string): { string }

Splits _input_ into parts based on a _pattern_ delimiter and returns a Table of the parts, followed by a Table of the matched delimiters.

**Example**

    local parts, delimiters = Dash.splitOn(
        "The quick brown fox jumps over the lazy dog",
        " "
    )

    print(parts)
    Output: {
        [1] = "The",
        [2] = "quick",
        [3] = "brown",
        [4] = "fox",
        [5] = "jumps",
        [6] = "over",
        [7] = "the",
        [8] = "lazy",
        [9] = "dog"

    print(delimiters)
        [1] = " ",
        [2] = " ",
        [3] = " ",
        [4] = " ",
        [5] = " ",
        [6] = " ",
        [7] = " ",
        [8] = " "

### startsWith

Strings

    startsWith(input: string, prefix: string): boolean

Checks if _input_ starts with the string _start_.

**Examples**

    startsWith("Fun Roblox Games", "Fun") --> true

    startsWith("Chess", "Fun") --> false

### trim

Strings

    trim(input: string): string

Remove any whitespace at the start and end of the _input_ string.

**Example**

    Dash.trim("\n\t\rhello world   ") --> "hello world"

## Functions

These utilities are helpful for working with functions.

### memoize

Functions

    type ResolverFunction = (...any) -> string

    memoize(func: Types.AnyFunction, resolver: ResolverFunction?): Types.AnyFunction

Creates a function that memoizes the result of `func`. The memoized function will cache results based on the arguments provided. If a resolver function is provided, it will be used to generate the cache key from the arguments.

**Examples**

    local function add(a, b)
        return a + b
    end

    local memoizedAdd = memoize(add)
    print(memoizedAdd(1, 2)) -- Calculates and caches: 3
    print(memoizedAdd(1, 2)) -- Returns from cache: 3

    -- With custom resolver
    local memoizedWithResolver = memoize(add, function(a, b)
        return string.format("%d_%d", a, b)
    end)

**Usage**

  * Use memoization for expensive computations that are called frequently with the same arguments
  * The resolver function can be used to customize how arguments are used to generate cache keys
  * Be mindful of memory usage as cached results are stored indefinitely

### forEachArgs

Functions

    forEachArgs(handler: Types.AnyFunction, ...: Value): ()

Iterates through the tail arguments in order, including nil values up to the argument list length.

Calls the _handler_ for each entry.

### identity

Functions

    identity(...)

The identity function, which simply returns its input parameters.

Can be used to make it clear that a handler returns its inputs.

### isCallable

Functions

    isCallable<T>(value: T): boolean

Returns `true` if the value can be called i.e. you can write `value(...)`.

### noop

Functions

    noop()

A function which does nothing.

Can be used to make it clear that a handler has no function.

### chain

Functions

    chain(("test"):gmatch("t"), ("test"):gmatch("e"))

Returns a stateful iterator that returns elements from the first iterable until it is exhausted, then proceeds to the next iterator until all the iterators are exhausted.

### debounce

Functions

    -- Numeric delay: trailing by default
    local debouncedGreeting = debounce(function(name: string)
        print(`Hi, {name}!`)
    end, 0.3)
    debouncedGreeting("Hugh")

    -- Options as third arg: leading/trailing toggles; wait stays second arg
    local debouncedLeading = debounce(function(v)
        print("Leading", v)
    end, 0.2, { leading = true, trailing = false })

    local debouncedTrailing = debounce(function(v)
        print("Trailing", v)
    end, 0.2, { leading = false, trailing = true })

Creates and returns a new debounced version of the passed function which will postpone its execution until after `wait` seconds have elapsed since the last time it was invoked.

Defaults: leading = false, trailing = true.

### throttle

Functions

    -- Numeric delay: immediate then trailing with latest args
    local throttledGreeting = throttle(function(name: string) print(`Hi, {name}!`)
    end, 0.3)
    throttledGreeting("Hugh")

    -- Options as third arg: configure leading/trailing; wait stays second arg
    local throttledLeadingOnly = throttle(function(v)
        print("Leading", v)
    end, 0.2, { leading = true, trailing = false })

    local throttledTrailingOnly = throttle(function(v)
        print("Trailing", v)
    end, 0.2, { leading = false, trailing = true })

Creates and returns a new throttled version of the passed function which will ensure that the function is called at most once during the specified wait period. If called multiple times during the wait period, only the first call will be executed immediately, and subsequent calls will be ignored until the wait period has elapsed.

  * Leading=true triggers immediately when outside the throttle window.
  * Trailing=true schedules a single call at the end of the window with the latest args.

The last call will always be done after the same delay. e.g.

    local throttled = throttle(function(v) print(v)
    end, 0.1)
    for i = 1, 10 do
        throttled(i)
    end

would result in

    1
    10

`throttle` is useful for preventing a function from being called too often, e.g. when reacting to resize events.

## Classes

These utilities are helpful for working with classes.

### Error

Classes

    Error.new(name: string, message: string, tags: Table?)

Create an error object with a specified name and message.

In native Lua, errors can only be string values. At Roblox, we can take advantage of throwing error objects to provide structured information about problems that occur.

The tags table stores rich information about an error which can be provided when it is thrown and later passed to a logging endpoint.

Throwing an error instance captures its stack trace, avoiding the need to explicitly use xpcall.

**Fields**

Name | Description
`name: string` | The name of the error
`message: string` | A message which will be formatted with Dash.format if the error is thrown
`tags: Table` | A table to store custom rich information about the error
`stack: string?` | The value of `debug.traceback()` when the error is thrown

**Methods**

Name | Description
`:joinTags(tags: Table?)` | Return a new error instance containing the tags provided joined to any existing tags of the current error instance.
`:throw(tags: Table?)` | Throw an error.

The stack of the error is captured and stored.

If tags are provided, a new error is created and thrown with the joined tags of this instance.

**Static Methods**

Name | Description
`.new(name: string, message: string, tags: Table?)` | Returns a new `Error` instance
`.is(other: any)` | Returns `true` if _other_ is an `Error` instance

**Usage**

In general, errors should not be used during normal control flow.

### Symbol

Classes

Create a symbol with a specified name. Upper snake-case is recommended as the symbol is a constant, unless you are linking the symbol conceptually to a different string.

Symbols are useful when you want a value that isn't equal to any other type, for example, if you want to store a unique property on an object that won't be accidentally accessed with a simple string lookup.

**Static Methods**

Name | Description
`.new(name: string)` | Returns a new unique `Symbol` instance with called _name_
`.is(other: any)` | Returns `true` if _other_ is a `Symbol` instance

**Example**

    local CHEESE = Symbol.new("CHEESE")
    local FAKE_CHEESE = Symbol.new("CHEESE")
    print(CHEESE == CHEESE) --> true
    print(CHEESE == FAKE_CHEESE) --> false
    print(tostring(CHEESE)) --> "Symbol.new(CHEESE)"

### class

Classes

Create a class called _name_ with the specified _constructor_. The constructor should return a plain table which will be turned into an instance of _Class_ from a call to `Class.new(...)`.

**Instance Methods**

Name | Description
`:toString(): string` | Returns a string representation of the class
`:equals(other: any):boolean` | Returns `true` if the instance is equal to _other_
`:_init()` | A private function which is called once the instance has been initialized

**Static Methods**

Name | Description
`.new(...): Table` | Returns a new instance of the class
`.isInstance(value: any): boolean` | Returns `true` if _value_ is an instance of the class

**Examples**

    -- Create a simple Vehicle class
    local Vehicle = class("Vehicle", function(wheelCount: number) return
            speed = 0,
            wheelCount = wheelCount
    end)
    function Vehicle:drive(speed)
        self.speed = speed
    end
    -- Create a car instance
    local car = Vehicle.new(4)
    -- car.wheelCount --> 4
    -- car.speed --> 0
    -- Drive the car
    car:drive(10)
    -- car.speed --> 10

**Usage**

  * When using Dash classes, private fields should be prefixed with `_` to avoid accidental access.
  * A private field should only be accessed by a method of the class itself, though Dash does not restrict this in code.
  * Public fields are recommended when there is no complex access logic e.g. `position.x`

## Symbols

Symbol definitions.

### None

Symbols

A symbol representing nothing, that can be used in place of nil as a key or value of a table, where nil is illegal.

Utility functions can check for the None symbol and treat it like a nil value.

**Usage**

Use cases include:

  1. Creating an ordered list with undefined values in it
  2. Creating a map with a key pointing to a nil value

## Debugging

These utilities assist with debugging Lua code.

### assertEqual

Debugging | Maps

    assertEqual(left: any, right: any, formattedErrorMessage: string?): ()

Performs a simple equality check and throws an error if _left_ is not equal to _right_.

The formatted error message can be customized, which by default provides serialization of both inputs using Dash.pretty.

The `left` and `right` values are available to be referenced in the formatted message.

### cycles

Debugging | Tables

    cycles(value: any, initialCycles: Cycles?): Cycles

Get information about the number of times references to the same table values appear in a data structure.

Operates on cyclic structures, and returns a Cycles object for a given _value_ by walking it recursively.

**Cycles**

Name | Type | Description
---|---|---
`omit` | `{ any }` | An array of keys which should not be visited
`visited` | `Set<Table>` | A set of tables which were visited recursively
`refs` | `Map<Table, number>` | A map from table to unique index in visit order
`nextRef` | `number` | The number to use for the next unique table visited

### format

Debugging | Strings

    format(formatString: string, ...): string

Returns the _format_ string with placeholders `{...}` substituted with readable representations of the subsequent arguments. This function is a simpler & more powerful version of `string.format`, inspired by `format!` in Rust.

  * `{}` formats and prints the next argument using `:format()` if available, or a suitable default representation depending on its type.
  * `{blah}` formats and prints the key "blah" of the 1st argument
  * `{2}` formats and prints the 2nd argument.
  * `{#2}` prints the length of the 2nd argument. Display parameters can be combined after a `:` in the curly braces. Any format parameters used in `string.format` can be used here, along with these extras:
  * `{:?}` formats any value using `pretty`.
  * `{:#?}` formats any value using multiline `pretty`.

**Examples**

    local props = {"teeth", "claws", "whiskers", "tail"}
    format("{} is in {:#?}", "whiskers", props)
    --> [[whiskers is in {"teeth", "claws", "whiskers", "tail"}]]

    format("The time is {:02}:{:02}", 2, 4) --> "The time is 02:04"

    format("The color blue is #{:06X}", 255) --> "The color blue is #0000FF"

**Usage**

  * Escape `{` with `{{` and `}` similarly with `}}`.
  * See <https://developer.roblox.com/articles/Format-String> for a complete list of formating options and further use cases.

### formatValue

Debugging | Strings

    formatValue(value: any, displayString: string): string

Format a specific _value_ using the specified _displayString_.

**Examples**

    formatValue(255, "06X") --> "0000FF"

    formatValue(255.5) --> "255.5"

**See**

  * Dash.format \- see format for a full description of valid display strings.

### pretty

Debugging | Tables | Strings

    pretty(object: any, options: PrettyOptions?): string

Return a pretty string serialization of _object_.

This implementation deals with cycles in tables and can neatly display metatables.

Optionally use an indented multiline string, limit the depth of tables, omit or pick keys.

**PrettyOptions**

Name | Type | Description
---|---|---
`depth` | `number?` | The maximum depth of ancestors of a table to display
`omit` | `{ any }?` | An array of keys which should not be visited
`multiline` | `boolean?` | Whether to use multiple lines (default = false)
`noQuotes` | `boolean?` | Whether to drop the quotation marks around strings. By default, this is true for table keys
`indent` | `string?` | The indent string to use (default = "\t")
`visited` | `Set<Table>?` | A set of tables which have already been visited and should be referred to by reference
`cycles` | `Cycles?` | A cycles object returned from `cycles` to aid reference display

**See**

  * Dash.cycles


# png-luau

PNG encoder/decoder for Luau. The decoder supports all valid PNG files, bit depths, color types, interlacing, and transparency chunks.

## Installation

This library is built for all Luau runtimes and Roblox projects.

### Wally

Add `png-luau` to your `wally.toml`:

```toml
png-luau = "sircfenner/png-luau@0.2.1"

### Releases

Pre-built versions are available in [GitHub releases](https://github.com/sircfenner/png-luau/releases):

- `png.luau` is a bundled single-file version of the library
- `png.rbxm` is a Roblox model file

## Decoding

To decode a PNG image, call the `decode` function with a buffer containing the file contents:

```Luau
local PNG = require("@vendor/png-luau")

local png = PNG.decode(file)

This returns a table with the following type:

```Luau
    width: number,
    height: number,
    pixels: buffer,
    readPixel: (x: number, y: number) -> (number, number, number, number)

The `pixels` buffer contains the decoded pixels in 32-bit RGBA format, top-to-bottom and left-to-right.

The `readPixel` function takes a pixel coordinate starting from (1, 1) in the top-left corner and returns the color information for that pixel (red, green, blue, alpha in the range 0-255).

The `decode` function takes an optional second parameter, which is a table specifying decoding options. Currently, the only valid option is `allowIncorrectCRC`, a boolean which defaults to false. It exists only for testing purposes and may be removed in future versions.

Known limitations:

- Attempting to decode an invalid PNG file will throw an error
- All ancillary chunks other than tRNS are currently skipped (other than CRC32 checks) when decoding
- Images are transformed into 32-bit RGBA pixel data after decoding, regardless of original bit depth and color type
- Files greater than 1GB in size or yielding greater than 1GB of image data after decompression (equivalent to ~16k x 16k resolution) cannot be decoded as they do not fit in a single Luau buffer

## Encoding

To encode a PNG image, call the `encode` function with a buffer containing the pixel data in 32-bit RGBA format as well as a table containing `width` and `height`:

```Luau
local PNG = require("@vendor/png-luau")

local file = PNG.encode(pixelBuffer, {
    width = 256,
    height = 128,
})

This returns a buffer containing the encoded PNG file.

Known limitations:

- Pixel data for encoding must be in 32-bit RGBA format as described above
- Images will be encoded in this same format - there is no support for writing other bit depths or color types
- Encoded images will never be interlaced or use transparency chunks
- As with decoding, the Luau buffer size cap of 1GB limits the maximum size of image data and encoded files

## License

This project is available under the MIT license. See [LICENSE](LICENSE) for details.

Some tests are derived from:

- [pngsuite](http://www.schaik.com/pngsuite/pngsuite.html)
- [imagetestsuite](https://code.google.com/archive/p/imagetestsuite/wikis/PNGTestSuite.wiki)
- [javapng](https://github.com/kerner1000/javapng/tree/master)


[ #  Code](https://code.google.com/archive/) [ ## Archive ](https://code.google.com/archive/) Skip to content

  * [Google](https://www.google.com/)
  * [About Google](https://www.google.com/intl/en/about/)
  * [Privacy](https://www.google.com/intl/en/policies/privacy/)
  * [Terms](https://www.google.com/intl/en/policies/terms/)


# alien-signals-luau

A translation of [alien-signals](https://github.com/stackblitz/alien-signals) to Luau. Read more about the design on the source repository.

## Usage

#### Basic APIs

```luau
local signals = require("alien-signals")
local signal = signals.signal
local computed = signals.computed
local effect = signals.effect

local count, setCount = signal(1)
local doubleCount = computed(function()
    return count() * 2
end)

effect(function()
    print(`Count is: {count()}`)
end) -- print: "Count is: 1"

print(doubleCount()) -- 2

setCount(2) -- print: "Count is: 2"

print(doubleCount()) -- 4

#### Effect Scope

```luau
local signals = require("alien-signals")
local signal = signals.signal
local effect = signals.effect
local effectScope = signals.effectScope

local count, setCount = signal(1)

local stopScope = effectScope(function()
    effect(function()
        print(`Count in scope: {count()}`)
    end) -- print: "Count in scope: 1"
end)

setCount(2) -- print: "Count in scope: 2"

stopScope()

setCount(3) -- no print

## Tests

```bash
lune run tests
# or
lute tests/init.luau

## Benchmarks

```bash
lune run benchmarks/propagate
# or
lute benchmarks/propagate.luau


# Int64 Luau

Available on:

-   [Wally](https://wally.run/) as `dekkonot/int64`
-   [npm](https://www.npmjs.com/) as `@dekkonot/int64`

Implementation of arithmetic and bitwise operations for **unsigned** 64-bit integers in pure Luau. Utilizes `vector` objects to pack the integers efficiently, meaning it avoids expensive table accesses and allocations.

Major features:

-   Arithmetic (addition, subtraction, mutiplication, division, modulo, and exponentiation)
-   Bitwise operations (everything implemented in `bit32` as of this time except for `replace`/`extract`)
-   Convenience functions for converting to and from other forms of data (hex strings, buffers, etc)

This does not implement `math` library functionality! Implementations of things like `math.random` are far beyond scope for this library, and implementation of things like `math.sin` are prohibitively complex and incredibly slow. It would also be very difficult to write tests for these that were appropriately exhaustive and it's irresponsible to release them into the world without tests.

This module is made as fast as is reasonably possible. However, they are still a fair bit slower than native integers; this will hopefully not be a surprise. You should expect very good performance, but it's possible that depending upon your use case storing two 32-bit integers and operating on them will be faster.

If you wish to contribute to this module, whether it be through optimizations or new functionality, please open a pull request.

## API

| [Constructors](#constructors)           | [Destructors](#destructors)           | [Constants](#constants) |
| :-------------------------------------- | :------------------------------------ | :---------------------- |
| [`from_f64`](#from_f64)                 | [`to_f64`](#to_f64)                   | [`ZERO`](#ZERO)         |
| [`from_dec_string`](#from_dec_string)   | [`to_dec_string`](#to_dec_string)     | [`ONE`](#ONE)           |
| [`from_pair`](#from_pair)               | [`to_pair`](#to_pair)                 | [`TWO`](#TWO)           |
| [`from_u32`](#from_u32)                 | [`to_quartet`](#to_quartet)           | [`MAX`](#MAX)           |
| [`from_buffer`](#from_buffer)           | [`to_buffer`](#to_buffer)             | [`MAX_U32`](#MAX_U32)   |
| [`from_byte_string`](#from_byte_string) | [`write_to_buffer`](#write_to_buffer) | [`MAX_F64`](#MAX_F64)   |
|                                         | [`to_byte_string`](#to_byte_string)   | [`MAX_F32`](#MAX_F32)   |
|                                         | [`to_hex_string`](#to_hex_string)     |                         |
|                                         | [`to_bin_string`](#to_bin_string)     |                         |

| [Logical](#logical)     | [Arithmetic](#arithmetic) | [Bitwise](#bitwise)     |
| :---------------------- | :------------------------ | :---------------------- |
| [`gt`](#gt)             | [`add`](#add)             | [`band`](#band)         |
| [`gt_equal`](#gt_equal) | [`sub`](#sub)             | [`bor`](#bor)           |
| [`lt`](#lt)             | [`mult`](#mult)           | [`bxor`](#bxor)         |
| [`lt_equal`](#lt_equal) | [`div`](#div)             | [`bnot`](#bnot)         |
|                         | [`pow`](#pow)             | [`lshift`](#lshift)     |
|                         |                           | [`rshift`](#rshift)     |
|                         |                           | [`arshift`](#arshift)   |
|                         |                           | [`lrotate`](#lrotate)   |
|                         |                           | [`rrotate`](#rrotate)   |
|                         |                           | [`countlz`](#countlz)   |
|                         |                           | [`countrz`](#countrz)   |
|                         |                           | [`btest`](#btest)       |
|                         |                           | [`byteswap`](#byteswap) |

### Constructors

#### `from_f64`

```luau
int64.from_f64(f64: number): vector

Constructs a 64-bit integer from the passed `f64`. Put more plainly, converts a normal Luau number to a 64-bit integer.

The number is truncated into an integer first. Note that Luau numbers cannot accurately represent integers past `2 ^ 53`.

#### `from_dec_string`

```luau
int64.from_dec_string(str: string): vector

Returns the provided value parsed as a 64-bit integer. Expects the provided string to contain only the digits 0-9 and will error if it does not.

Leading zeros are accepted and parsed appropriately.

Due to the implementation, the resulting integer will wrap around if it is too large to fit in a 64-bit integer rather than erroring.

#### `from_pair`

```luau
int64.from_pair(most: number, least: number): vector

Constructs a 64-bit integer from the passed `u32` values.

The provided `most` value fills the upper 32 bits of the integer, and the provided `least` value fills the lower 32-bits.

#### `from_u32`

```luau
int64.from_u32(u32: number): vector

Constructs a 64-bit integer from the passed `u32`.

This number is truncated in a 32-bit integer, even if it is larger than the max value.

#### `from_buffer`

```luau
int64.from_buffer(buf: buffer, offset: number?): vector

Reads a `u64` from the provided buffer. If offset is provided, reads from that spot in the buffer. Otherwise, reads from the beginning.

This function reads a little-endian value from the buffer.

#### `from_byte_string`

```luau
int64.from_byte_string(str: string, offset: number?): vector

Reads a `u64` from the provided string. If offset is provided, reads from that point in the string. Otherwise starts at the beginning.

This function reads a little-endian value from the string.

### Destructors

#### `to_f64`

```luau
int64.to_f64(u64: vector): number

Converts the provided `u64` to an `f64` (or put plainly: a normal Luau number).

This function does not check for precision loss. `f64` values lose precision past `2 ^ 53`.

#### `to_dec_string`

```luau
int64.to_dec_string(u64: vector): string

Returns the provided value as a string of decimal digits.

Equivalent to formatting normal numbers with `%u` or calling `tostring` on them.

#### `to_pair`

```luau
int64.to_pair(u64: vector): (number, number)

Converts the provided `u64` into two 32-bit integers.

This returns the most significant portion of the number first.

#### `to_quartet`

```luau
int64.to_quartet(u64: vector): (number, number, number, number)

Converts the provided `u64` into four 16-bit integers.

This returns the most significant portion of the number first.

#### `to_buffer`

```luau
int64.to_buffer(u64: vector): buffer

Converts the provided `u64` to a buffer.

The integer is written as a little-endian value.

#### `write_to_buffer`

```luau
int64.write_to_buffer(b: buffer, u64: vector, offset: number)

Writes the provided `u64` to the provided buffer. The value is written to the buffer at the provided offset.

The integer is written as a little-endian value.

#### `to_byte_string`

```luau
int64.to_byte_string(u64: vector): string

Converts the provided `u64` to string of binary data.

The integer is written as if it were little-endian.

#### `to_hex_string`

```luau
int64.to_hex_string(u64: vector): string

Converts the provided `u64` to a string of 16 hexadecimal digits.

The returned string will always be 16 bytes and the number is formatted as if it were big-endian. It also always uses lowercase letters.

#### `to_bin_string`

```luau
int64.to_bin_string(u64: vector): string

Converts the provided `u64` to a string of 64 binary digits.

The returned string will always be 64 bytes and the number is formatted as if it were big-endian.

### Constants

#### `ZERO`

A constant representing the 64-bit representation of `0`.

#### `ONE`

A constant representating the 64-bit representation of `1`.

#### `TWO`

A constant representating the 64-bit representation of `2`.

#### `MAX`

A constant representing the maximum possible 64-bit value (`18446744073709551615`, or `2 ^ 64 - 1`).

#### `MAX_U32`

A constant representing the maximum possible 32-bit value (`4294967295`, or `2 ^ 32 - 1`).

#### `MAX_F64`

A constant representing the maximum integer that is exactly representable by a normal Luau number (`9007199254740992` or `2 ^ 53`).

#### `MAX_F32`

A constant representing the maximum integer that is exactly representable by a 32-bit floating point value (`16777216`, or `2 ^ 24`).

### Logical

#### `gt`

```luau
int64.gt(lhs: vector, rhs: vector): boolean

Returns whether `lhs` is greater than `rhs`.

#### `gt_equal`

```luau
int64.gt_equal(lhs: vector, rhs: vector): boolean

Returns whether `lhs` is greater than or equal to `rhs`.

#### `lt`

```luau
int64.lt(lhs: vector, rhs: vector): boolean

Returns whether `lhs` is less than `rhs`.

#### `lt_equal`

```luau
int64.lt_equal(lhs: vector, rhs: vector): boolean

Returns whether `lhs` is less than or equal to `rhs`.

### Arithmetic

#### `add`

```luau
int64.add(augend: vector, addend: vector): vector

Calculates the sum of the two provided values. Equivalent to `+` for normal integers.

If the sum is equal to or greater than `2 ^ 64`, the returned value will overflow rather than expanding beyond 64 bits.

#### `sub`

```luau
int64.sub(minuend: vector, subtrahend: vector): vector

Calculates the difference of the two provided values. Equivalent to `-` for normal integers.

If the difference is less than `0`, the returned value will overflow rather than going negative.

#### `mult`

```luau
int64.mult(multiplier: vector, multiplicand: vector): vector

Calculates the product of the two provided values. Equivalent to `*` for normal integers.

If the product is greater than or equal to `2 ^ 64`, the returned value will overflow rather than expanding beyond 64 bits.

#### `div`

```luau
int64.div(dividend: vector, divisor: vector): (vector, vector)

Calculates the quotient of the two provided values and returns it, along with the remainder.

Equivalent to `//` and `%` for normal integers.
This function will error if `divisor` is `0`.

#### `pow`

```luau
int64.pow(base: vector, power: number): vector

Calculates the result of `base` raised to `power`. Equivalent to `^` for normal integers. `power` is interpreted as a 32-bit integer.

If the result is greater than or equal to `2 ^ 64`, the returned value will overflow rather than expanding beyond 64 bits.

Additionally, `0 ^ 0` is treated as being `1`.

### Bitwise

#### `band`

```luau
int64.band(lhs: vector, rhs: vector): vector

Computes the bitwise AND of the two provide values.

This does not accept a vararg like the `bit32` equivalent for performance reasons.

#### `bor`

```luau
int64.bor(lhs: vector, rhs: vector): vector

Computes the bitwise OR of the two provide values.

This does not accept a vararg like the `bit32` equivalent for performance reasons.

#### `bxor`

```luau
int64.bxor(lhs: vector, rhs: vector): vector

Computes the bitwise XOR of the two provide values.

This does not accept a vararg like the `bit32` equivalent for performance reasons.

#### `bnot`

```luau
int64.bnot(u64: vector): vector

Computes the bitwise negation of the provided value.

#### `lshift`

```luau
int64.lshift(u64: vector, n: number): vector

Shifts the provided `u64` logically left by `n` bits.

This function will error if `n` is negative.

#### `rshift`

```luau
int64.rshift(u64: vector, n: number): vector

Shifts the provided `u64` logically right by `n` bits.

This function will error if `n` is negative.

#### `arshift`

```luau
bit64.arshift(u64: vector, n: number): vector

Shifts the provided `u64` arithmetically right by `n` bits. Since these numbers are unsigned, this effectively just copies the most significant bit into the empty space rather than filling them with zeros.

This function will error if `n` is negative.

#### `lrotate`

```luau
int64.lrotate(u64: vector, n: number): vector

Rotates the bits of the provided `u64` left by `n` bits.

If `n` is negative, this is equivalent to `rrotate`. Otherwise, if `n` is greater than 64-bits, it will wrap around.

#### `rrotate`

```luau
int64.rrotate(u64: vector, n: number): vector

Rotates the bits of the provided `u64` right by `n` bits.

If `n` is negative, this is equivalent to `lrotate`. Otherwise, if `n` is greater than 64-bits, it will wrap around.

#### `countlz`

```luau
int64.countlz(u64: vector): number

Returns the number of consecutive zero bits in the provided `u64` starting from the left-most (most significant) bit.

#### `countrz`

```luau
int64.countrz(u64: vector): number

Returns the number of consecutive zero bits in the provided `u64` starting from the right-most (least significant) bit.

#### `btest`

```luau
int64.btest(lhs: vector, rhs: vector): boolean

Returns a boolean describing whether the bitwise AND of `lhs` and `rhs` are different than zero.

This does not accept a vararg like the `bit32` equivalent for performance reasons.

#### `byteswap`

```luau
int64.byteswap(u64: vector): vector

Returns the provided `u64` with the order of bytes swapped.


# StateQ: A Finite State Machine (FSM) in Luau

An intuitive fully-typed Finite State Machine in [Luau](https://luau-lang.org/) that supports async transitions by queueing events, developed for use in Roblox experiences.

This project is licensed under the terms of the MIT license. See [LICENSE.md](https://github.com/busycityguy/finite-state-machine-luau/blob/main/LICENSE.md) for details.

## This project is a work in progress

Tests need to be written and the API may receive small changes while this project is being finalized for a first release.

# What's a finite state machine?

A Finite State Machine (FSM) provides a way to enforce specific logical flow among a set of States. Given an Event, the FSM responds by looking up the corresponding Transition for that Event in its current State. A Transition is a callback function that is invoked when an Event is given to the FSM, and it returns the next State for the FSM to move to.

The FSM enforces that Events can only be called when a Transition is defined for that Event in its current State
by erroring if an Event is called in an invalid state (a state with no Transition defined for that Event).

# Included features

The FSM provides 5 signals that can be listened to during handling of an event.
These signals, transition callbacks, and state changes are processed in the following order:

![SequenceDiagram](https://github.com/BusyCityGuy/finite-state-machine-luau/assets/55513323/9ace09e3-a16e-474b-83ca-aac91cd69492)

1. Fire `beforeEvent` signal
    - with arguments `eventName`, `beforeState`
1. Call `transition.beforeAsync()` (required, returns next state)
    - with the VarArgs from `:handle(eventName, transitionArgs...)`
1. Fire `leavingState` signal
    - with arguments `beforeState, afterState`
1. Update `_currentState` to next state
1. Fire `stateEntered` signal
    - with arguments `afterState, beforeState`
1. Call `transition.afterAsync()` (if specified)
    - with the VarArgs from `:handle(eventName, transitionArgs...)`
1. Fire `afterEvent` signal
    - with arguments `eventName, afterState, beforeState`
1. Fire `finished` signal if next state from `beforeAsync()` was `nil`
    - with argument `beforeState`

Transitions can be asynchronous, which is supported by queuing each Event submitted via :handle() and processing them in First-In-First-Out (FIFO) order. The next Event starts processing immediately after the previous Event's handler fires `afterEvent`.

The FSM can Finish if a Transition does not return a "next state" during an event marked as "canBeFinal".
In such a case, the FSM will fire a `finished` event and will error if any further Events are handled.
A `nil` state means the FSM has Finished.

# Example usage

A simple state machine diagram for a light switch may look like this, where

- States are represented as rectangles, and squares indicate the State can be Final
- Events are represented as capsules

![ExampleUsage](https://github.com/BusyCityGuy/finite-state-machine-luau/assets/55513323/3d5b2118-91ea-4427-ac2d-688fb0094d1f)

```luau
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local StateQ = require(ReplicatedStorage.Packages.StateQ)

local LightState = {
    On = "On",
    Off = "Off",

local Event = {
    SwitchOn = "SwitchOn",
    SwitchOff = "SwitchOff",

local light = StateQ.new(LightState.On, {
    [Event.SwitchOn] = {
        canBeFinal = true,
        from = {
            [LightState.Off] = { -- From state
                beforeAsync = function() -- Transition
                    print("Light is transitioning to On")
                    for i = 1, 100 do
                        -- do some action to increase brightness of a light here
                        task.wait()
                    end
                    return LightState.On -- To next state
                end,
                afterAsync = function()
                    print("Light is now On")
                end,
        },
    },
    [Event.SwitchOff] = {
        canBeFinal = true,
        from = {
            [LightState.On] = {
                beforeAsync = function()
                    print("Light is transitioning to Off")
                    return LightState.Off
                end,
        },
    },
})

light:handle(Event.SwitchOff) -- prints "Light is transitioning to Off"
light:handle(Event.SwitchOn) -- prints "Light is transitioning to On", increases brightness over time, and then prints "Light is now On"
light:handle(Event.SwitchOn) -- warns "Illegal event `SwitchOn` called during state `On`" with a stack trace

# Detailed system flowchart

![Flowchart](https://github.com/BusyCityGuy/finite-state-machine-luau/assets/55513323/5b3a5c8f-fd42-4021-b3a8-6da1256644d8)

# Installation

## Rojo users

If your project is set up to build with Rojo, the preferred installation method is using [Wally](https://wally.run/). Add this to your `wally.toml` file:

```bash
> StateQ = "busycityguy/stateq@0.0.6"

If you're not using Wally, you can add this repository as a submodule of your project by running the following command:

```bash
> git submodule add <https://github.com/BusyCityGuy/finite-state-machine-luau> path/to/your/dependencies

If you want to avoid submodules too, you can download the `.zip` file from the [latest release](https://github.com/BusyCityGuy/finite-state-machine-luau/releases/latest) page.

## Non-Rojo users

If you aren't using Rojo, you can download the `.rbxm` file from the [latest release](https://github.com/BusyCityGuy/finite-state-machine-luau/releases/latest) page and drag it into Roblox Studio, placing the `Packages` folder in `ReplicatedStorage`.

# Feedback

If you have other questions, bugs, feature requests, or feedback, please [open an issue](https://github.com/BusyCityGuy/finite-state-machine-luau/issues)!

# Contributing

See the [Contributing readme](CONTRIBUTING.md).


# React Luau

    A comprehensive, but not exhaustive, translation of ReactJS 17.x into Luau.

React Luau is a declarative library for building user interfaces. It's a highly-tuned translation of ReactJS and currently based on React 17.

* **Declarative:** React makes it easy to create interactive UIs. Design simple views for each state in your application, and React will efficiently update and render just the right components when your data changes. Declarative views make your code more predictable, simpler to understand, and easier to debug.
* **Component-Based:** Build encapsulated components that manage their own state, then compose them to make complex UIs. Since component logic is written in Luau instead of managed with Roblox's Instances, you can easily pass rich data through your code and keep the state out of the data model.
* **Tuned for Roblox:** Luau is not Javascript, so we deviate from ReactJS in certain places for a more ergonomic programming experience in Luau and with Roblox's wider programming model. For example, React Luau introduces Bindings, a form of signals-based state that doesn't re-render, for highly-efficient animations driven by React.

[Learn how to use React Luau in your project](https://www.react-luau.dev/).

## Examples

We have several examples [on the website](https://www.react-luau.dev/). Here is the first one to get you started:

```luau
local React = require(Packages.React)
local ReactRoblox = require(Packages.ReactRoblox)

local e = React.createElement

local function HelloMessage(props: {
    name: string,
})
    return e("TextLabel", {
        AnchorPoint = Vector2.new(0.5, 0.5),
        Position = UDim2.fromScale(0.5, 0.5),
        AutomaticSize = Enum.AutomaticSize.XY,
        Text = `Hello, {props.name}!`,
    })
end

local function App()
    return e("ScreenGui", {}, {
        MyMessage = e(HelloMessage, {
            name = "Taylor",
        }),
    })
end

local root = ReactRoblox.createRoot(Instance.new("Folder"))
root:render(ReactRoblox.createPortal(e(App), Players.LocalPlayer.PlayerGui))

This example will render "Hello, Taylor!" into a TextLabel on the screen.

### License

React Luau is [MIT licensed](./LICENSE). Go do cool stuff with it!


# Planck, an ECS Scheduler

An Agnostic Scheduler, inspired by Bevy Schedules and Flecs Pipelines and Phases.

## Installation

You can install Planck with Wally

```toml
[dependencies]
Planck = "yetanotherclown/planck@0.2.0"

## What is Planck?

Planck is a standalone scheduler, which allows you to execute code on specific events, with certain conditions, and in a particular order.

This scheduler is library agnostic, which means that it *doesn't matter* which ECS library your using or if you're even using an ECS.
You can use this with [Jecs], [Matter], [ECR], and other Luau ECS Libraries.

## Does any of this really matter?

Yes, and no.
Your ECS code should be able to run in any order, without any conditions, and without concern for which event it's running on, as long as *it is* running.

The order of execution, and conditions both serve to *optimize* your code. Some systems don't need to run every frame, which is why we have conditions.
And the actual order of execution is to reduce latency between changes and effects in your ECS world.

Let's say we have `systemA` and `systemB`. `systemA` modifies data in our world which `systemB` depends on.
If `systemA` runs *after* `systemB`, then `systemB` will have to wait a whole frame for the modifications to be made.
This is called being *off-by-a-frame*, and this is why we care about the order of execution.

## What's Next?

You may not completely understand what's written above. That's fine.

For now, you should read the [Official Documentation](https://yetanotherclown.github.io/planck) on how to get started with Planck. These concepts will be explained more in depth as you read.

## Quick Overview

While it's highly suggested you read the documentation, here is a quick overview of Planck's API.

### The Scheduler

This is the core of Planck, this is where you add your Systems and set your Phases, Pipelines, and Run Conditions.

```luau
local Planck = require("@packages/Planck")
local Scheduler = Planck.Scheduler

local Jecs = require("@packages/Jecs")
local World = Jecs.World

local world = World.new()
local state = {}

local scheduler = Scheduler.new(world, state)

### Systems

Systems are really simple, they are just functions which run on an event or in a loop.

```luau
local function systemA(world, state)
    -- ...
end

return systemA

And to add it to our Scheduler,

```luau
-- ...

local systemA = require("@shared/systems/systemA")

local scheduler = Scheduler.new(world, state)
    :addSystem(systemA)

> [!NOTE]
> Systems will not run by default without scheduling it on a [Phase](https://yetanotherclown.github.io/planck/docs/getting_started/phases) or using [`Scheduler:run()`](https://yetanotherclown.github.io/planck/api/Scheduler#run)/[`Scheduler:runAll()`](https://yetanotherclown.github.io/planck/api/Scheduler#runAll).
> You can also use the [RunService Plugin](https://yetanotherclown.github.io/planck/docs/plugins/runservice) to have systems run on [`RunService.Heartbeat`](https://create.roblox.com/docs/reference/engine/classes/RunService#Heartbeat) by default.

### Phases

Phases are used to split up your frame into different sections, this allows us to schedule our systems to run at different moments of a given frame.

```luau
local Planck = require("@packages/Planck")
local Scheduler = Planck.Scheduler
local Phase = Planck.Phase

-- ...

local systemA = require("@shared/systems/systemA")

local myPhase = Phase.new("myPhase")

local scheduler = Scheduler.new(world, state)
    :insert(myPhase)
    :addSystem(systemA, myPhase)

Planck has lots of built-in Phases that should work for most cases,
→ [Built-in Phases](https://yetanotherclown.github.io/planck/docs/getting_started/phases#built-in-phases)

### Pipelines

Pipelines are ordered groups of Phases, they make working with larger collections of Phases (which all run on the same event) easier.

```luau
local Phase = Planck.Phase
local Pipeline = Planck.Pipeline
local Scheduler = Planck.Scheduler

local PreUpdate = Phase.new()
local Update = Phase.new()
local PostUpdate = Phase.new()

local UpdatePipeline = Pipeline.new()
    :insert(PreUpdate)
    :insert(Update)
    :insert(PostUpdate)

local scheduler = scheduler.new(world)
    :insert(UpdatePipeline, RunService, "Heartbeat")

> [!TIP]
> The `UpdatePipeline` seen here, already exists in Planck! It's a built-in Pipeline that you can use without any setup.
> See all [Built-in Phases](https://yetanotherclown.github.io/planck/docs/getting_started/phases#built-in-phases).

### Conditions

When we run all our systems every frame, there are a lot of systems that may not actually need to run. Run Conditions allow us to
run our Systems, Phases and Pipelines only sometimes.

```luau
local function condition(world)
    if someCondition then
        return true
    else
        return false
    end
end

local scheduler = Scheduler.new(world)
    :addRunCondition(systemA, condition)
    :addRunCondition(somePhase, condition)
    :addRunCondition(somePipeline, condition)

Conditions can be useful, but you should use them carefully. It's suggested that you read our page on
[Conditions](https://yetanotherclown.github.io/planck/docs/design/conditions) to see some useful examples and learn when you should use them.

## Inspiration

Planck's API design is heavily influenced by the [Bevy Engine](https://bevyengine.org/), with Schedules, RunConditions, and more.
Planck also draws inspiration from [Flecs](https://www.flecs.dev/) for Pipelines and Phases.

We're combining the simple, and beloved API of Bevy with the concept of Pipelines and Phases.

[Jecs]: https://ukendio.github.io/jecs
[Matter]: https://matter-ecs.github.io/matter
[ECR]: https://centau.github.io/ecr/


# Planck Scheduler

An Agnostic Scheduler for ECS

[Get Started](https://yetanotherclown.github.io/planck/docs/intro)[API](https://yetanotherclown.github.io/planck/api)

## Library Agnostic

It does not matter what ECS library you are using, this scheduler is agnostic!

## Inspired by Flecs and Bevy

This library takes inspiration from Flecs for Phases and Pipelines, and Bevy Schedules for the API design.

## Designed to be Ergonomic

The API for this library is designed to be ergonomic, and allow for a great developer experience.

It's fully typed, allowing for strict typing and great intellisense.

## Plugins System

Planck features a Plugin system, allowing for easy incorporation of other tools and libraries into the Scheduler.

Planck features two Plugins for the [Jabby Debugger](https://yetanotherclown.github.io/planck/docs/plugins/jabby), [Matter Debugger](https://yetanotherclown.github.io/planck/docs/plugins/matter_debugger), and [Matter Hooks](https://yetanotherclown.github.io/planck/docs/plugins/matter_hooks)

[Learn More](https://yetanotherclown.github.io/planck/docs/plugins)


Here's a quick navigation of Planck's Docs.

### Getting Started

  * [Introduction](https://yetanotherclown.github.io/planck/docs/getting_started/introduction)
  * [The Scheduler](https://yetanotherclown.github.io/planck/docs/getting_started/scheduler)
  * [Systems](https://yetanotherclown.github.io/planck/docs/getting_started/systems)
  * [Phases](https://yetanotherclown.github.io/planck/docs/getting_started/phases)
  * [Order of Execution](https://yetanotherclown.github.io/planck/docs/getting_started/order)

### Designing with Planck

  * [Introduction](https://yetanotherclown.github.io/planck/docs/design)
  * [Systems](https://yetanotherclown.github.io/planck/docs/design/systems)
  * [Phases & Pipelines](https://yetanotherclown.github.io/planck/docs/design/phases-and-pipelines)
  * [Conditions](https://yetanotherclown.github.io/planck/docs/design/conditions)

### Setup Guides

  * [Matter](https://yetanotherclown.github.io/planck/docs/setup_guides/matter)
  * [Jecs](https://yetanotherclown.github.io/planck/docs/setup_guides/jecs)

### Plugins

  * [Plugins](https://yetanotherclown.github.io/planck/docs/plugins)
  * [Jabby](https://yetanotherclown.github.io/planck/docs/plugins/jabby)
  * [Matter Hooks](https://yetanotherclown.github.io/planck/docs/plugins/matter_hooks)
  * [Matter Debugger](https://yetanotherclown.github.io/planck/docs/plugins/matter_debugger)
  * [RunService Phases](https://yetanotherclown.github.io/planck/docs/plugins/runservice)

### API

  * [Scheduler](https://yetanotherclown.github.io/planck/api/Scheduler)
  * [Pipeline](https://yetanotherclown.github.io/planck/api/Pipeline)
  * [Phase](https://yetanotherclown.github.io/planck/api/Phase)


# RegExp for Luau
A regular expression library for Luau. Adapted from a regex implementation by github user Blockzez (https://github.com/Blockzez).

## API
Create a regex with the `new` function:
`RegExp.new(pattern: string, flags: string) -> RegularExpression`

A resulting RegularExpression has the following methods:
* `RegularExpression:exec(str: string) -> Match`
* `RegularExpression:test(str: string) -> boolean`

The `Match` object resulting from `exec` has the following fields:
* `[1..n]` - The array potion of the `Match` object contains captured groups
* `n` - The length of the array of resulting captured groups
* `index` - The index in the original string where the match begins
* `input` - The original string passed into `exec`

### Flags
The following flags can be provided via the second argument to `RegExp.new`:
* "i" - ignoreCase
* "g" - global
* "m" - multiline


# PyLua - Embedded Python for Luau

> For v0.2 docs, see [docs/0.2/README.md](docs/0.2/README.md).

Run Python inside Luau (e.g., Roblox). PyLua is a compact, CPython‑inspired interpreter you can embed in Luau projects.

## Quick Start

### Installation

#### Manual

- Download the latest release from Releases
- Place the PyLua module in your ReplicatedStorage for roblox projects, or your project folder for other Luau projects.

#### Jelly

- Install with jelly

```shell
jelly install omouta/pylua

#### Wally

- Add PyLua to wally.toml

```toml
pylua = "omouta/pylua@MAJOR.MINOR.PATCH"

- Install with wally

```shell
wally install

### Use PyLua

Embed and run a bit of Python:

```lua
local PyLua = require("./src/PyLua")
local py = PyLua.new()

py:execute([[x = 2 + 3]])
print(py:getGlobal("x")) -- 5

local result = py:eval("sum([1, 2, 3])")
print(result) -- 6

## Docs and examples

- Docs index: `docs/README.md`
- Architecture overview: `docs/ARCHITECTURE.md`
- Examples: `examples/`

## Status

- Version: `0.3.1`
- Target: Python 3.12 and below (3.13+ out of scope)
- Roadmap: `internalDocs/ROADMAP.md`

## Contributing

Issues and PRs welcome. See `CONTRIBUTING.md` for guidelines.

## License

MIT - see [`LICENSE`](./LICENSE).


# Cryo

    A collection of methods for working with immutable data in a functional way for Roblox Lua.

Cryo is a library that helps you write more terse code that deals with immutable data. It includes traditional FP list primitives like `map`, `filter`, and `foldLeft`, as well as tools inspired by JavaScript like joining dictionaries.

Cryo works well to make [Rodux](https://github.com/Roblox/rodux) reducers cleaner!

## Installation

This project can be specified as a dependency via rotriever:
```toml
Cryo = "github.com/roblox/cryo-internal@1.0.3"

## Documentation

Documentation for Cryo is available on [the official documentation website](https://roblox.github.io/cryo-internal).

## License

Licensed under the MIT license ([LICENSE.txt](LICENSE.txt) or http://opensource.org/licenses/MIT).

### Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the MIT license, shall be licensed as above, without any additional terms or conditions.

Take a look at the [contributing guide](CONTRIBUTING.md) for guidelines on how to contribute to Cryo.


This is the documentation home for Cryo, a collection of utilities for working with immutable data in Roblox Lua.


# API Reference

## Constants¶

### None¶

Represents a value that is intentionally present, but should be interpreted as `nil`.

`Cryo.None` is used by included utilities to make removing values more ergonomic.

## isEmpty¶

    Cryo.isEmpty(table) -> bool

Tells whether the given table is empty in constant time. Works on both dictionary-like and list-like tables.

## Dictionary¶

Defines utilities for working with dictionary-like tables.

Dictionaries can be indexed by any value, but don't have the ordering expectations that lists have.

### Dictionary.equals¶

    Cryo.Dictionary.equals(...dictionaries) -> boolean

Compares two or more dictionaries shallowly for value equality. Returns `true` if all dictionaries have the same keys and values, `false` otherwise.

### Dictionary.filter¶

    Cryo.Dictionary.filter(dictionary, predicate) -> dictionary

Constructs a new dictionary by filtering elements with the given predicate. The predicate should be a function that accepts the values and keys of the dictionary and which returns a boolean.

    local function isValueEven(value)
        return value % 2 == 0
    end

    local dictionary = {
        a = 1,
        a = 2,
        c = 3

    local evenValues = Dictionary.filter(dictionary, isValueEven)

    local function isKeyUpper(_value, key)
        return string.upper(key) == key
    end

    local dictionary = {
        a = 1,
        B = 2,
        c = 3

    local upperKeys = Dictionary.filter(dictionary, isKeyUpper)

### Dictionary.join¶

    Cryo.Dictionary.join(...dictionaries) -> dictionary

Combine a number of dictionary-like tables into a new table.

Keys specified in later tables will overwrite keys in previous tables.

Use `Cryo.None` as a value to remove a value from the resulting table. This is necessary because Lua does not distinguish between a value not being present in a table and a value being `nil`.

`Dictionary.join` is handy when dealing with configuration tables, where we might want default values.

    local defaultConfig = {
        frobulateProngs = true,
        frobulator = "less"

    local function doSomething(userConfig)
        local config = Dictionary.join(defaultConfig, userConfig)

        if config.frobulateProngs then
            useFrobulator(config.frobulator)
        end
    end

### Dictionary.keys¶

    Cryo.Dictionary.keys(dictionary) -> list

Combines all keys from the dictionary into a list-like table.

### Dictionary.map¶

    Cryo.Dictionary.map(dictionary, callback) -> dictionary

Constructs a new dictionary by using the callback to replace elements in the dictionary. `callback` should be a function like the following.

    callback(value, key) -> newValue, newKey?

If `newKey` is not provided, the original key will be used.

### Dictionary.omit¶

    Cryo.Dictionary.omit(dictionary, ...keys) -> dictionary

Creates a new dictionary without the given keys.

### Dictionary.union¶

    Cryo.Dictionary.union(dictionaryA, dictionaryB) -> dictionary

Creates a new dictionary that contains all the keys and values from both dictionaries. If a key is present in both dictionaries, the value from `dictionaryB` will be used.

### Dictionary.values¶

    Cryo.Dictionary.values(dictionary) -> list

Combines all values from the dictionary into a list-like table.

## List¶

Defines utilities for working with 'list-like' tables.

Lists are tables indexed with continuous integer keys starting at 1.

### List.equals¶

    Cryo.List.equals(...lists) -> boolean

Compares two or more lists shallowly for value equality. Returns `true` if all lists have the same values in the same order, `false` otherwise.

### List.filter¶

    Cryo.List.filter(list, callback) -> list

Constructs a new list by filtering elements with the given callback.

`callback` is expected to be a function with this signature:

    callback(value, index) -> result

If `result` is truthy, the value will be included in the new list. Otherwise, the value will be ignored.

### List.filterMap¶

    Cryo.List.filterMap(list, callback) -> list

Combines the functionality of `List.filter` and `List.map`.

`callback` should be a function with this signature:

    callback(value, index) -> result

If `result` is `nil`, the value will not be included in the new list. Any other result will add the `result` value to the new list.

### List.find¶

    Cryo.List.find(list, value) -> index | nil

Searches for the value in the given list and returns the position of the first occurence of the value. If the value is not found, `find` will return `nil`.

### List.findWhere¶

    Cryo.List.findWhere(list, predicate) -> index | nil

`predicate` should be a function with this signature:

    predicate(value, index) -> result

Searches for the first index in the given list for which `predicate` returns a truthy value. If the predicate never returns a truthy value, `findWhere` will return `nil`.

### List.foldLeft¶

    Cryo.List.foldLeft(list, callback, initialValue) -> value

Iterates over the given list and uses the given callback to calculate the returned value.

`callback` should be a function with this signature:

    callback(accumulator, value, index) -> newAccumulator

`callback` will be invoked once for each value in the list. It should return a new accumulator value that will be passed to the next invocation of `callback`.

`foldLeft` is sometimes known as `reduce`. It can be used to perform operations like summing a list:

    local list = {1, 2, 3}
    local function add(a, b)
        return a + b
    end

    local sum = List.foldLeft(list, add, 0)

### List.foldRight¶

    Cryo.List.foldRight(list, callback, initialValue) -> value

Similar to `List.foldLeft`, except the list is traversed from right-to-left instead of from left-to-right. `foldRight` is useful when working with operations that aren't associative.

### List.join¶

    Cryo.List.join(...lists) -> list

Combines all the given lists into a single new list.

### List.map¶

    Cryo.List.map(list, callback) -> list

Constructs a new list by using the callback to replace elements in the list. `callback` should be a function like the following.

    callback(element, index) -> newElement

### List.removeIndex¶

    Cryo.List.removeIndex(list, index) -> list

Creates a new list without the given index.

### List.removeRange¶

    Cryo.List.removeRange(list, startIndex, endIndex) -> list

Creates a new list without the given range. The indexes `startIndex` and `endIndex` will not be included in the returned list.

### List.removeValue¶

    Cryo.List.removeValue(list, value) -> list

Creates a new list without any occurences of the given value.

### List.replaceIndex¶

    Cryo.List.replaceIndex(list, index, value) -> list

Creates a new list with the new value at the given index. The function will throw an error if the index is larger than the list length.

### List.reverse¶

    Cryo.List.reverse(list) -> list

Creates a new list with the same elements from the given list, but in the opposite order.

### List.sort¶

    Cryo.List.sort(list[, callback]) -> list

Constructs a new list that consists of the elements of the input list, but sorted using the given callback.

`List.sort` is the immutable equivalent of Lua's `table.sort`.

### List.toSet¶

    Cryo.List.toSet(list) -> dictionary

Creates a dictionary where each value in the given list corresponds to a key in the dictionary with a value of true.


# 🐈 Lynx

[**Documentation ⚡ lynx.luau.page**](https://lynx.luau.page)

Lynx is a simple and fast Luau web framework for Lune. Lynx is inspired by [Hono](https://github.com/honojs/hono) and shares a similar API.

```luau
local app = Lynx.new()

app:get('/', function(c)
    return c:text('Lynx!')
end)

app:serve()

## Features

- 🧩 **Simple API** - Convenient methods for creating routes and generating a response
- ⚡ **Fast Routing** - Efficient routing using a radix tree
- 📦 **Intuitive Middleware** - Extend request handling easily

## Documentation

Read the documentation at [lynx.luau.page](https://lynx.luau.page).


# Lynx Web Framework

A fast and simple Luau web framework for Lune.

[ Get started ](https://lynx.luau.page/getting-started) [ View on GitHub ](https://github.com/Nicell/lynx)

Simple API

Convenient methods for creating routes

Fast Routing

Efficient routing using a radix tree

Intuitive Middleware

Extend request handling easily

Powered by Lune

Designed for the Lune runtime


Send complex data between Rust and Roblox Luau via Wasynth using JSON.

## Install

cargo add lingua_luau

## But why‽

The Rust ecosystem contains a lot of valuable tooling for Luau developers. However, for many of us, we're not able to incorporate it into our work, because we're restricted to working inside of sandboxed Luau runtimes.

Wasynth provides an exciting opportunity to bridge that gap, allowing basic WASM to run completely under Luau for the first time. However, it's pretty low level, meaning developers have to implement bespoke strategies for communicating across the WASM boundary. Generating bindings could help here, but a more immediate, compatible, and technologically straightforward solution is desirable.

That's where Lingua comes in. Leveraging Rust's serde-json crate and Roblox's JSON encoding methods, Lingua allows Rust and Luau code to freely communicate complex structured data without setting up dedicated bindings or complex binary formats.

Lingua provides friendly APIs on both the Rust and Luau side so that end users don't have to worry about memory management or other implementation details.

## Long-term vision

Lingua's ultimate goal is to become obsolete as Rust/Luau interop becomes more complete. An obvious first step would be to replace JSON with a dedicated binary format. Ultimately, it would be good to see proper bindgen tech built out, to minimise the overhead of interfacing between Rust and Luau.

## License

Licensed the same way as all of my open source projects: BSD 3-Clause + Security Disclaimer.

As with all other projects, you accept responsibility for choosing and using this project.

See [LICENSE](./LICENSE) or [the license summary](https://github.com/dphfox/licence) for details.


Quill

The best all-in-one lightweight Roblox game framework.

## 🪶 Quill

**Quill** is a Luau framework designed to simplify your workflow's setup.

## 📦 Installation

The Quill packages are available for [Wally](https://wally.run/package/featherfall-org/quill-core) and [Pesde](https://pesde.dev/packages/featherfall/quill_core).

```toml
# wally.toml
[dependencies]
quill = "featherfall-org/quill-[CRATE]@LATEST" # Replace LATEST with your desired version & [CRATE] with your crate of choice, for example featherfall-org/quill-core

```sh
pesde add featherfall/quill_[CRATE] # Replace [CRATE] with your crate of choice, for example featherfall/quill_core

A roblox model file (`.rbxm`) containing all crates is also built on every push and is available [here](https://nightly.link/featherfall-org/quill/workflows/build.yml/main/quill.zip).

## 📚 Getting Started

[Take me to the documentation →](https://featherfall-org.github.io/quill)

## 📝 License

Quill is licensed under the [MIT License](LICENSE).

## ⚒ Contributing

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in Quill by you, shall be licensed as MIT, without any additional terms or conditions.