icidasset / elm-binary / Binary


type Bits

The binary sequence.

Use converters to make Bits.

Binary.fromIntegers [ 0, 1, 0, 1 ]

empty : Bits

An empty binary sequence.

Converters

fromHex : String -> Bits

Convert a hex string to list of binary numbers.

>>> fromHex "8" |> toIntegers
[ 1, 0, 0, 0 ]

toHex : Bits -> String

Convert a list of binary numbers to a hex string.

>>> toHex <| fromIntegers [ 1, 0, 0, 0 ]
"8"

fromDecimal : Basics.Int -> Bits

Convert a decimal to Bits.

>>> fromDecimal 8 |> toIntegers
[ 1, 0, 0, 0 ]

toDecimal : Bits -> Basics.Int

Convert Bits to a decimal.

>>> toDecimal <| fromIntegers [ 1, 0, 0, 0 ]
8

fromIntegers : List Basics.Int -> Bits

Convert a list of integers to Bits.

Everything below zero and zero itself becomes a 0 bit, and everything above zero becomes a 1 bit.

>>> fromIntegers [ 1, 0, 0, 0 ] |> toHex
"8"

toIntegers : Bits -> List Basics.Int

Convert Bits to a list of integers.

>>> toIntegers <| fromHex "8"
[ 1, 0, 0, 0 ]

fromBooleans : List Basics.Bool -> Bits

Convert a list of booleans to Bits.

>>> fromBooleans [ True, False, False, False ] |> toHex
"8"

toBooleans : Bits -> List Basics.Bool

Convert Bits to a list of booleans.

>>> toBooleans <| fromHex "8"
[ True, False, False, False ]

fromString : Basics.Int -> String -> Bits

Convert a string to Bits.

The resulting bits will represent the decimal value (ie. code point) of each character (it uses String.toList).

The first argument determines how many bits are used per decimal value.

WARNING: This assumes each character will fit into the range you defined. For example, an emoji will not fit in 8 bits, so you can't use fromString 8. That said, you can use fromStringAsUtf8 to make sure each character is split up into multiple UTF-8 characters.

-- 1 character
-- Code points: [ 0x1F936 ]

>>> "🤶"
..>   |> fromString 32
..>   |> toHex
"0001F936"

-- 3 characters
-- Code points: [ 0x61, 0x62, 0x63 ]
-- These hexadecimal values are each 8 bits long.

>>> "abc"
..>   |> fromString 8
..>   |> toHex
"616263"

fromStringAsUtf8 : String -> Bits

Convert a string to UTF-8 Bits.

This will convert every character into multiple UTF-8 codepoints, if necessary, and then use 8 bits per character.

NOTE: This is not the same as the fromString 8 function! Which assumes every character is already UTF-8. Or, in other words, assumes that each character's codepoint is below 128.

>>> "🤶"
..>   |> fromStringAsUtf8
..>   |> toHex
"F09FA4B6"

>>> "abc"
..>   |> fromStringAsUtf8
..>   |> toHex
"616263"

toString : Basics.Int -> Bits -> String

Convert Bits to a string.

  1. Splits the bits in chunks of the given number
  2. Each chunk is converted to a decimal (code point)
  3. Each code point is translated to a character
  4. The list of characters is converted to a string

The first argument determines how many bits are used per decimal value (ie. how large the chunks are).

>>> "0001F936"
..>   |> fromHex
..>   |> toString 32
"🤶"

>>> "616263"
..>   |> fromHex
..>   |> toString 8
"abc"

Bitwise Operators

and : Bits -> Bits -> Bits

AND operator.

--     0101 (decimal 5)
-- AND 0011 (decimal 3)
--   = 0001 (decimal 1)

>>> Binary.and
..>   (fromHex "5")
..>   (fromHex "3")
ensureSize 4 (fromHex "1")

or : Bits -> Bits -> Bits

OR operator.

--    0101 (decimal 5)
-- OR 0011 (decimal 3)
--  = 0111 (decimal 7)

>>> Binary.or
..>   (fromHex "5")
..>   (fromHex "3")
fromHex "7"

xor : Bits -> Bits -> Bits

XOR operator.

--     0101 (decimal 5)
-- XOR 0011 (decimal 3)
--   = 0110 (decimal 6)

>>> Binary.xor
..>   (fromHex "5")
..>   (fromHex "3")
fromHex "6"

not : Bits -> Bits

NOT operator.

-- NOT 0111 (decimal 7)
--   = 1000 (decimal 8)

>>> Binary.not
..>   (fromIntegers [ 0, 1, 1, 1 ])
fromIntegers [ 1, 0, 0, 0 ]

Bit Shifting

shiftLeftBy : Basics.Int -> Bits -> Bits

Arithmetic/Logical left shift.

-- LEFTSHIFT 00010111 (decimal 23)
--         = 00101110 (decimal 46)

>>> [ 0, 0, 0, 1, 0, 1, 1, 1 ]
..>   |> fromIntegers
..>   |> shiftLeftBy 1
..>   |> toIntegers
[ 0, 0, 1, 0, 1, 1, 1, 0 ]

shiftRightBy : Basics.Int -> Bits -> Bits

Arithmetic right shift.

-- ARI-RIGHTSHIFT 10010111 (decimal 151)
--              = 11001011 (decimal 203)

>>> [ 1, 0, 0, 1, 0, 1, 1, 1 ]
..>   |> fromIntegers
..>   |> shiftRightBy 1
..>   |> toIntegers
[ 1, 1, 0, 0, 1, 0, 1, 1 ]

shiftRightZfBy : Basics.Int -> Bits -> Bits

Logical right shift.

-- LOG-RIGHTSHIFT 10010111 (decimal 151)
--              = 00001011 (decimal 11)

>>> [ 0, 0, 0, 1, 0, 1, 1, 1 ]
..>   |> fromIntegers
..>   |> shiftRightZfBy 1
..>   |> toIntegers
[ 0, 0, 0, 0, 1, 0, 1, 1 ]

rotateLeftBy : Basics.Int -> Bits -> Bits

Rotate a binary sequence to the left.

NOTE: Make sure your binary sequence is of the correct size before rotating! Rotating 8 bits is not always the same as, for example, 16 bits.

>>> rotateLeftBy 1 (ensureSize 32 <| fromHex "17")
ensureSize 32 (fromHex "2E")

>>> rotateLeftBy 2 (ensureSize 32 <| fromHex "96")
ensureSize 32 (fromHex "258")

rotateRightBy : Basics.Int -> Bits -> Bits

Rotate a binary sequence to the right.

NOTE: Make sure your binary sequence is of the correct size before rotating! Rotating 8 bits is not always the same as, for example, 16 bits.

>>> rotateRightBy 1 (ensureSize 64 <| fromHex "17")
ensureSize 64 (fromHex "800000000000000B")

>>> rotateRightBy 1 (ensureSize 32 <| fromHex "96")
ensureSize 32 (fromHex "4B")

>>> rotateRightBy 5 (ensureSize 32 <| fromHex "96")
ensureSize 32 (fromHex "B0000004")

Mathematical Operators

add : Bits -> Bits -> Bits

Add two sets of bits together.

-- ADD 1011
--     1011
--  = 10110

>>> add
..>   (fromIntegers [ 1, 0, 1, 1 ])
..>   (fromIntegers [ 1, 0, 1, 1 ])
fromIntegers [ 1, 0, 1, 1, 0  ]

>>> add
..>   (fromIntegers [ 1, 1, 1, 0, 1 ])
..>   (fromIntegers [ 1, 0, 1, 0 ])
fromIntegers [ 1, 0, 0, 1, 1, 1  ]

subtract : Bits -> Bits -> Bits

Subtract two sets of bits from each other.

-- SUBTRACT 1011
--          11
--        = 1010

>>> subtract
..>   (fromIntegers [ 1, 0, 1, 1 ])
..>   (fromIntegers [ 1, 1 ])
fromIntegers [ 1, 0, 0, 0  ]

>>> subtract
..>   (fromIntegers [ 1, 0, 0, 0, 1 ])
..>   (fromIntegers [ 0, 0, 1, 0, 0 ])
fromIntegers [ 0, 1, 1, 0, 1  ]

Utilities

append : Bits -> Bits -> Bits

Merge two binary sequences.

>>> append
..>   (fromIntegers [ 1, 0, 0, 0 ])
..>   (fromIntegers [ 1, 0, 1, 0 ])
fromIntegers [ 1, 0, 0, 0, 1, 0, 1, 0 ]

chunksOf : Basics.Int -> Bits -> List Bits

Split the binary sequence in multiple chunks.

>>> fromIntegers [ 1, 0, 0, 0, 1, 0, 1, 0 ]
..>   |> chunksOf 4
..>   |> List.map toIntegers
[ [ 1, 0, 0, 0 ]
, [ 1, 0, 1, 0 ]
]

concat : List Bits -> Bits

Concat multiple binary sequences.

>>> [ fromIntegers [ 1, 0, 0, 0 ]
..> , fromIntegers [ 0, 1, 0, 1 ]
..> ]
..>   |> concat
..>   |> toDecimal
133

dropLeadingZeros : Bits -> Bits

Drops the leading zeros of a binary sequence.

>>> dropLeadingZeros (fromIntegers [ 0, 0, 1, 0 ])
fromIntegers [ 1, 0 ]

ensureSize : Basics.Int -> Bits -> Bits

Ensure the binary sequence length is of certain size.

>>> ensureSize 4 (fromIntegers [ 1, 0 ])
fromIntegers [ 0, 0, 1, 0 ]

makeIsometric : Bits -> Bits -> ( Bits, Bits )

Makes two sequences isometric (equal in size).

>>> makeIsometric
..>   (fromIntegers [ 0, 1, 0 ])
..>   (fromIntegers [ 1, 0, 0, 0 ])
( fromIntegers [ 0, 0, 1, 0 ]
, fromIntegers [ 1, 0, 0, 0 ]
)

width : Bits -> Basics.Int

Get the amount of bits in a binary sequence.

>>> fromIntegers [ 1, 0, 0, 0 ]
..>   |> width
4