From 8a9d509a20a8c797437ec08447ac61b36c7a77de Mon Sep 17 00:00:00 2001 From: Steven Vandevelde Date: Sat, 5 Jan 2019 16:16:40 +0100 Subject: [PATCH] 2.1.0 --- CHANGELOG.md | 11 +++-- docs.json | 2 +- elm.json | 2 +- src/Binary.elm | 111 +++++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 118 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7670cde..aa3a3bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,14 @@ # Changelog +#### 2.1.0 + +Added `fromStringAsUtf8` function. + + #### 2.0.1 & 2.0.2 -- More performance improvements +More performance improvements. #### 2.0.0 @@ -17,12 +22,12 @@ #### 1.3.0 -- Added `append` function. +Added `append` function. #### 1.2.1 -- Does no longer drop leading zeros when using `fromHex` and/or `toHex`. +Does no longer drop leading zeros when using `fromHex` and/or `toHex`. #### 1.2.0 diff --git a/docs.json b/docs.json index 87dfc7a..2f09577 100644 --- a/docs.json +++ b/docs.json @@ -1 +1 @@ -[{"name":"Binary","comment":"\n\n@docs Bits, empty\n\n\n# Converters\n\n@docs fromHex, toHex, fromDecimal, toDecimal, fromIntegers, toIntegers, fromBooleans, toBooleans, fromString, toString\n\n\n# Bitwise Operators\n\n@docs and, or, xor, not\n\n\n# Bit Shifting\n\n@docs shiftLeftBy, shiftRightBy, shiftRightZfBy, rotateLeftBy, rotateRightBy\n\n\n# Mathematical Operators\n\n@docs add, subtract\n\n\n# Utilities\n\n@docs append, chunksOf, concat, dropLeadingZeros, ensureSize, makeIsometric, width\n\n","unions":[{"name":"Bits","comment":" **The binary sequence.**\n\nUse converters to make `Bits`.\n\n Binary.fromIntegers [ 0, 1, 0, 1 ]\n\n","args":[],"cases":[]}],"aliases":[],"values":[{"name":"add","comment":" Add two sets of bits together.\n\n -- ADD 1011\n -- 1011\n -- = 10110\n\n >>> add\n ..> (fromIntegers [ 1, 0, 1, 1 ])\n ..> (fromIntegers [ 1, 0, 1, 1 ])\n fromIntegers [ 1, 0, 1, 1, 0 ]\n\n >>> add\n ..> (fromIntegers [ 1, 1, 1, 0, 1 ])\n ..> (fromIntegers [ 1, 0, 1, 0 ])\n fromIntegers [ 1, 0, 0, 1, 1, 1 ]\n\n","type":"Binary.Bits -> Binary.Bits -> Binary.Bits"},{"name":"and","comment":" AND operator.\n\n -- 0101 (decimal 5)\n -- AND 0011 (decimal 3)\n -- = 0001 (decimal 1)\n\n >>> Binary.and\n ..> (fromHex \"5\")\n ..> (fromHex \"3\")\n ensureSize 4 (fromHex \"1\")\n\n","type":"Binary.Bits -> Binary.Bits -> Binary.Bits"},{"name":"append","comment":" Merge two binary sequences.\n\n >>> append\n ..> (fromIntegers [ 1, 0, 0, 0 ])\n ..> (fromIntegers [ 1, 0, 1, 0 ])\n fromIntegers [ 1, 0, 0, 0, 1, 0, 1, 0 ]\n\n","type":"Binary.Bits -> Binary.Bits -> Binary.Bits"},{"name":"chunksOf","comment":" Split the binary sequence in multiple chunks.\n\n >>> fromIntegers [ 1, 0, 0, 0, 1, 0, 1, 0 ]\n ..> |> chunksOf 4\n ..> |> List.map toIntegers\n [ [ 1, 0, 0, 0 ]\n , [ 1, 0, 1, 0 ]\n ]\n\n","type":"Basics.Int -> Binary.Bits -> List.List Binary.Bits"},{"name":"concat","comment":" Concat multiple binary sequences.\n\n >>> [ fromIntegers [ 1, 0, 0, 0 ]\n ..> , fromIntegers [ 0, 1, 0, 1 ]\n ..> ]\n ..> |> concat\n ..> |> toDecimal\n 133\n\n","type":"List.List Binary.Bits -> Binary.Bits"},{"name":"dropLeadingZeros","comment":" Drops the leading zeros of a binary sequence.\n\n >>> dropLeadingZeros (fromIntegers [ 0, 0, 1, 0 ])\n fromIntegers [ 1, 0 ]\n\n","type":"Binary.Bits -> Binary.Bits"},{"name":"empty","comment":" An empty binary sequence.\n","type":"Binary.Bits"},{"name":"ensureSize","comment":" Ensure the binary sequence length is of certain size.\n\n >>> ensureSize 4 (fromIntegers [ 1, 0 ])\n fromIntegers [ 0, 0, 1, 0 ]\n\n","type":"Basics.Int -> Binary.Bits -> Binary.Bits"},{"name":"fromBooleans","comment":" Convert a list of booleans to `Bits`.\n\n >>> fromBooleans [ True, False, False, False ] |> toHex\n \"8\"\n\n","type":"List.List Basics.Bool -> Binary.Bits"},{"name":"fromDecimal","comment":" Convert a decimal to `Bits`.\n\n >>> fromDecimal 8 |> toIntegers\n [ 1, 0, 0, 0 ]\n\n","type":"Basics.Int -> Binary.Bits"},{"name":"fromHex","comment":" Convert a hex string to list of binary numbers.\n\n >>> fromHex \"8\" |> toIntegers\n [ 1, 0, 0, 0 ]\n\n","type":"String.String -> Binary.Bits"},{"name":"fromIntegers","comment":" Convert a list of integers to `Bits`.\n\nEverything below zero and zero itself becomes a `0` bit,\nand everything above zero becomes a `1` bit.\n\n >>> fromIntegers [ 1, 0, 0, 0 ] |> toHex\n \"8\"\n\n","type":"List.List Basics.Int -> Binary.Bits"},{"name":"fromString","comment":" Convert a string to `Bits`.\n\nThe resulting bits will represent the decimal value\n(ie. code point) of each character (it uses `String.toList`).\n\nThe first argument determines how many bits\nare used per decimal value.\n\n -- 1 character\n -- Code points: [ 0x1F936 ]\n\n >>> \"🤶\"\n ..> |> fromString 32\n ..> |> toHex\n \"0001F936\"\n\n -- 3 characters\n -- Code points: [ 0x61, 0x62, 0x63 ]\n -- These hexadecimal values are each 8 bits long.\n\n >>> \"abc\"\n ..> |> fromString 8\n ..> |> toHex\n \"616263\"\n\n","type":"Basics.Int -> String.String -> Binary.Bits"},{"name":"makeIsometric","comment":" Makes two sequences isometric (equal in size).\n\n >>> makeIsometric\n ..> (fromIntegers [ 0, 1, 0 ])\n ..> (fromIntegers [ 1, 0, 0, 0 ])\n ( fromIntegers [ 0, 0, 1, 0 ]\n , fromIntegers [ 1, 0, 0, 0 ]\n )\n\n","type":"Binary.Bits -> Binary.Bits -> ( Binary.Bits, Binary.Bits )"},{"name":"not","comment":" NOT operator.\n\n -- NOT 0111 (decimal 7)\n -- = 1000 (decimal 8)\n\n >>> Binary.not\n ..> (fromIntegers [ 0, 1, 1, 1 ])\n fromIntegers [ 1, 0, 0, 0 ]\n\n","type":"Binary.Bits -> Binary.Bits"},{"name":"or","comment":" OR operator.\n\n -- 0101 (decimal 5)\n -- OR 0011 (decimal 3)\n -- = 0111 (decimal 7)\n\n >>> Binary.or\n ..> (fromHex \"5\")\n ..> (fromHex \"3\")\n fromHex \"7\"\n\n","type":"Binary.Bits -> Binary.Bits -> Binary.Bits"},{"name":"rotateLeftBy","comment":" Rotate a binary sequence to the left.\n\n_NOTE: Make sure your binary sequence is of the correct size before rotating!\nRotating 8 bits is not always the same as, for example, 16 bits._\n\n >>> rotateLeftBy 1 (ensureSize 32 <| fromHex \"17\")\n ensureSize 32 (fromHex \"2E\")\n\n >>> rotateLeftBy 2 (ensureSize 32 <| fromHex \"96\")\n ensureSize 32 (fromHex \"258\")\n\n","type":"Basics.Int -> Binary.Bits -> Binary.Bits"},{"name":"rotateRightBy","comment":" Rotate a binary sequence to the right.\n\n_NOTE: Make sure your binary sequence is of the correct size before rotating!\nRotating 8 bits is not always the same as, for example, 16 bits._\n\n >>> rotateRightBy 1 (ensureSize 64 <| fromHex \"17\")\n ensureSize 64 (fromHex \"800000000000000B\")\n\n >>> rotateRightBy 1 (ensureSize 32 <| fromHex \"96\")\n ensureSize 32 (fromHex \"4B\")\n\n >>> rotateRightBy 5 (ensureSize 32 <| fromHex \"96\")\n ensureSize 32 (fromHex \"B0000004\")\n\n","type":"Basics.Int -> Binary.Bits -> Binary.Bits"},{"name":"shiftLeftBy","comment":" Arithmetic/Logical left shift.\n\n -- LEFTSHIFT 00010111 (decimal 23)\n -- = 00101110 (decimal 46)\n\n >>> [ 0, 0, 0, 1, 0, 1, 1, 1 ]\n ..> |> fromIntegers\n ..> |> shiftLeftBy 1\n ..> |> toIntegers\n [ 0, 0, 1, 0, 1, 1, 1, 0 ]\n\n","type":"Basics.Int -> Binary.Bits -> Binary.Bits"},{"name":"shiftRightBy","comment":" Arithmetic right shift.\n\n -- ARI-RIGHTSHIFT 10010111 (decimal 151)\n -- = 11001011 (decimal 203)\n\n >>> [ 1, 0, 0, 1, 0, 1, 1, 1 ]\n ..> |> fromIntegers\n ..> |> shiftRightBy 1\n ..> |> toIntegers\n [ 1, 1, 0, 0, 1, 0, 1, 1 ]\n\n","type":"Basics.Int -> Binary.Bits -> Binary.Bits"},{"name":"shiftRightZfBy","comment":" Logical right shift.\n\n -- LOG-RIGHTSHIFT 10010111 (decimal 151)\n -- = 00001011 (decimal 11)\n\n >>> [ 0, 0, 0, 1, 0, 1, 1, 1 ]\n ..> |> fromIntegers\n ..> |> shiftRightZfBy 1\n ..> |> toIntegers\n [ 0, 0, 0, 0, 1, 0, 1, 1 ]\n\n","type":"Basics.Int -> Binary.Bits -> Binary.Bits"},{"name":"subtract","comment":" Subtract two sets of bits from each other.\n\n -- SUBTRACT 1011\n -- 11\n -- = 1010\n\n >>> subtract\n ..> (fromIntegers [ 1, 0, 1, 1 ])\n ..> (fromIntegers [ 1, 1 ])\n fromIntegers [ 1, 0, 0, 0 ]\n\n >>> subtract\n ..> (fromIntegers [ 1, 0, 0, 0, 1 ])\n ..> (fromIntegers [ 0, 0, 1, 0, 0 ])\n fromIntegers [ 0, 1, 1, 0, 1 ]\n\n","type":"Binary.Bits -> Binary.Bits -> Binary.Bits"},{"name":"toBooleans","comment":" Convert `Bits` to a list of booleans.\n\n >>> toBooleans <| fromHex \"8\"\n [ True, False, False, False ]\n\n","type":"Binary.Bits -> List.List Basics.Bool"},{"name":"toDecimal","comment":" Convert `Bits` to a decimal.\n\n >>> toDecimal <| fromIntegers [ 1, 0, 0, 0 ]\n 8\n\n","type":"Binary.Bits -> Basics.Int"},{"name":"toHex","comment":" Convert a list of binary numbers to a hex string.\n\n >>> toHex <| fromIntegers [ 1, 0, 0, 0 ]\n \"8\"\n\n","type":"Binary.Bits -> String.String"},{"name":"toIntegers","comment":" Convert `Bits` to a list of integers.\n\n >>> toIntegers <| fromHex \"8\"\n [ 1, 0, 0, 0 ]\n\n","type":"Binary.Bits -> List.List Basics.Int"},{"name":"toString","comment":" Convert `Bits` to a string.\n\n1. Splits the bits in chunks of the given number\n2. Each chunk is converted to a decimal (code point)\n3. Each code point is translated to a character\n4. The list of characters is converted to a string\n\nThe first argument determines how many bits\nare used per decimal value (ie. how large the chunks are).\n\n >>> \"0001F936\"\n ..> |> fromHex\n ..> |> toString 32\n \"🤶\"\n\n >>> \"616263\"\n ..> |> fromHex\n ..> |> toString 8\n \"abc\"\n\n","type":"Basics.Int -> Binary.Bits -> String.String"},{"name":"width","comment":" Get the amount of bits in a binary sequence.\n\n >>> fromIntegers [ 1, 0, 0, 0 ]\n ..> |> width\n 4\n\n","type":"Binary.Bits -> Basics.Int"},{"name":"xor","comment":" XOR operator.\n\n -- 0101 (decimal 5)\n -- XOR 0011 (decimal 3)\n -- = 0110 (decimal 6)\n\n >>> Binary.xor\n ..> (fromHex \"5\")\n ..> (fromHex \"3\")\n fromHex \"6\"\n\n","type":"Binary.Bits -> Binary.Bits -> Binary.Bits"}],"binops":[]}] \ No newline at end of file +[{"name":"Binary","comment":"\n\n@docs Bits, empty\n\n\n# Converters\n\n@docs fromHex, toHex, fromDecimal, toDecimal, fromIntegers, toIntegers, fromBooleans, toBooleans, fromString, fromStringAsUtf8, toString\n\n\n# Bitwise Operators\n\n@docs and, or, xor, not\n\n\n# Bit Shifting\n\n@docs shiftLeftBy, shiftRightBy, shiftRightZfBy, rotateLeftBy, rotateRightBy\n\n\n# Mathematical Operators\n\n@docs add, subtract\n\n\n# Utilities\n\n@docs append, chunksOf, concat, dropLeadingZeros, ensureSize, makeIsometric, width\n\n","unions":[{"name":"Bits","comment":" **The binary sequence.**\n\nUse converters to make `Bits`.\n\n Binary.fromIntegers [ 0, 1, 0, 1 ]\n\n","args":[],"cases":[]}],"aliases":[],"values":[{"name":"add","comment":" Add two sets of bits together.\n\n -- ADD 1011\n -- 1011\n -- = 10110\n\n >>> add\n ..> (fromIntegers [ 1, 0, 1, 1 ])\n ..> (fromIntegers [ 1, 0, 1, 1 ])\n fromIntegers [ 1, 0, 1, 1, 0 ]\n\n >>> add\n ..> (fromIntegers [ 1, 1, 1, 0, 1 ])\n ..> (fromIntegers [ 1, 0, 1, 0 ])\n fromIntegers [ 1, 0, 0, 1, 1, 1 ]\n\n","type":"Binary.Bits -> Binary.Bits -> Binary.Bits"},{"name":"and","comment":" AND operator.\n\n -- 0101 (decimal 5)\n -- AND 0011 (decimal 3)\n -- = 0001 (decimal 1)\n\n >>> Binary.and\n ..> (fromHex \"5\")\n ..> (fromHex \"3\")\n ensureSize 4 (fromHex \"1\")\n\n","type":"Binary.Bits -> Binary.Bits -> Binary.Bits"},{"name":"append","comment":" Merge two binary sequences.\n\n >>> append\n ..> (fromIntegers [ 1, 0, 0, 0 ])\n ..> (fromIntegers [ 1, 0, 1, 0 ])\n fromIntegers [ 1, 0, 0, 0, 1, 0, 1, 0 ]\n\n","type":"Binary.Bits -> Binary.Bits -> Binary.Bits"},{"name":"chunksOf","comment":" Split the binary sequence in multiple chunks.\n\n >>> fromIntegers [ 1, 0, 0, 0, 1, 0, 1, 0 ]\n ..> |> chunksOf 4\n ..> |> List.map toIntegers\n [ [ 1, 0, 0, 0 ]\n , [ 1, 0, 1, 0 ]\n ]\n\n","type":"Basics.Int -> Binary.Bits -> List.List Binary.Bits"},{"name":"concat","comment":" Concat multiple binary sequences.\n\n >>> [ fromIntegers [ 1, 0, 0, 0 ]\n ..> , fromIntegers [ 0, 1, 0, 1 ]\n ..> ]\n ..> |> concat\n ..> |> toDecimal\n 133\n\n","type":"List.List Binary.Bits -> Binary.Bits"},{"name":"dropLeadingZeros","comment":" Drops the leading zeros of a binary sequence.\n\n >>> dropLeadingZeros (fromIntegers [ 0, 0, 1, 0 ])\n fromIntegers [ 1, 0 ]\n\n","type":"Binary.Bits -> Binary.Bits"},{"name":"empty","comment":" An empty binary sequence.\n","type":"Binary.Bits"},{"name":"ensureSize","comment":" Ensure the binary sequence length is of certain size.\n\n >>> ensureSize 4 (fromIntegers [ 1, 0 ])\n fromIntegers [ 0, 0, 1, 0 ]\n\n","type":"Basics.Int -> Binary.Bits -> Binary.Bits"},{"name":"fromBooleans","comment":" Convert a list of booleans to `Bits`.\n\n >>> fromBooleans [ True, False, False, False ] |> toHex\n \"8\"\n\n","type":"List.List Basics.Bool -> Binary.Bits"},{"name":"fromDecimal","comment":" Convert a decimal to `Bits`.\n\n >>> fromDecimal 8 |> toIntegers\n [ 1, 0, 0, 0 ]\n\n","type":"Basics.Int -> Binary.Bits"},{"name":"fromHex","comment":" Convert a hex string to list of binary numbers.\n\n >>> fromHex \"8\" |> toIntegers\n [ 1, 0, 0, 0 ]\n\n","type":"String.String -> Binary.Bits"},{"name":"fromIntegers","comment":" Convert a list of integers to `Bits`.\n\nEverything below zero and zero itself becomes a `0` bit,\nand everything above zero becomes a `1` bit.\n\n >>> fromIntegers [ 1, 0, 0, 0 ] |> toHex\n \"8\"\n\n","type":"List.List Basics.Int -> Binary.Bits"},{"name":"fromString","comment":" Convert a string to `Bits`.\n\nThe resulting bits will represent the decimal value\n(ie. code point) of each character (it uses `String.toList`).\n\nThe first argument determines how many bits\nare used per decimal value.\n\nWARNING: This assumes each character will fit into the range you defined.\nFor example, an emoji will not fit in 8 bits, so you can't use `fromString 8`.\nThat said, you can use `fromStringAsUtf8` to make sure each character\nis split up into multiple UTF-8 characters.\n\n -- 1 character\n -- Code points: [ 0x1F936 ]\n\n >>> \"🤶\"\n ..> |> fromString 32\n ..> |> toHex\n \"0001F936\"\n\n -- 3 characters\n -- Code points: [ 0x61, 0x62, 0x63 ]\n -- These hexadecimal values are each 8 bits long.\n\n >>> \"abc\"\n ..> |> fromString 8\n ..> |> toHex\n \"616263\"\n\n","type":"Basics.Int -> String.String -> Binary.Bits"},{"name":"fromStringAsUtf8","comment":" Convert a string to UTF-8 `Bits`.\n\nThis will convert every character into multiple UTF-8 codepoints,\nif necessary, and then use 8 bits per character.\n\nNOTE: This is not the same as the `fromString 8` function!\nWhich assumes every character is already UTF-8.\nOr, in other words, assumes that each character's codepoint is below 128.\n\n >>> \"🤶\"\n ..> |> fromStringAsUtf8\n ..> |> toHex\n \"F09FA4B6\"\n\n >>> \"abc\"\n ..> |> fromStringAsUtf8\n ..> |> toHex\n \"616263\"\n\n","type":"String.String -> Binary.Bits"},{"name":"makeIsometric","comment":" Makes two sequences isometric (equal in size).\n\n >>> makeIsometric\n ..> (fromIntegers [ 0, 1, 0 ])\n ..> (fromIntegers [ 1, 0, 0, 0 ])\n ( fromIntegers [ 0, 0, 1, 0 ]\n , fromIntegers [ 1, 0, 0, 0 ]\n )\n\n","type":"Binary.Bits -> Binary.Bits -> ( Binary.Bits, Binary.Bits )"},{"name":"not","comment":" NOT operator.\n\n -- NOT 0111 (decimal 7)\n -- = 1000 (decimal 8)\n\n >>> Binary.not\n ..> (fromIntegers [ 0, 1, 1, 1 ])\n fromIntegers [ 1, 0, 0, 0 ]\n\n","type":"Binary.Bits -> Binary.Bits"},{"name":"or","comment":" OR operator.\n\n -- 0101 (decimal 5)\n -- OR 0011 (decimal 3)\n -- = 0111 (decimal 7)\n\n >>> Binary.or\n ..> (fromHex \"5\")\n ..> (fromHex \"3\")\n fromHex \"7\"\n\n","type":"Binary.Bits -> Binary.Bits -> Binary.Bits"},{"name":"rotateLeftBy","comment":" Rotate a binary sequence to the left.\n\n_NOTE: Make sure your binary sequence is of the correct size before rotating!\nRotating 8 bits is not always the same as, for example, 16 bits._\n\n >>> rotateLeftBy 1 (ensureSize 32 <| fromHex \"17\")\n ensureSize 32 (fromHex \"2E\")\n\n >>> rotateLeftBy 2 (ensureSize 32 <| fromHex \"96\")\n ensureSize 32 (fromHex \"258\")\n\n","type":"Basics.Int -> Binary.Bits -> Binary.Bits"},{"name":"rotateRightBy","comment":" Rotate a binary sequence to the right.\n\n_NOTE: Make sure your binary sequence is of the correct size before rotating!\nRotating 8 bits is not always the same as, for example, 16 bits._\n\n >>> rotateRightBy 1 (ensureSize 64 <| fromHex \"17\")\n ensureSize 64 (fromHex \"800000000000000B\")\n\n >>> rotateRightBy 1 (ensureSize 32 <| fromHex \"96\")\n ensureSize 32 (fromHex \"4B\")\n\n >>> rotateRightBy 5 (ensureSize 32 <| fromHex \"96\")\n ensureSize 32 (fromHex \"B0000004\")\n\n","type":"Basics.Int -> Binary.Bits -> Binary.Bits"},{"name":"shiftLeftBy","comment":" Arithmetic/Logical left shift.\n\n -- LEFTSHIFT 00010111 (decimal 23)\n -- = 00101110 (decimal 46)\n\n >>> [ 0, 0, 0, 1, 0, 1, 1, 1 ]\n ..> |> fromIntegers\n ..> |> shiftLeftBy 1\n ..> |> toIntegers\n [ 0, 0, 1, 0, 1, 1, 1, 0 ]\n\n","type":"Basics.Int -> Binary.Bits -> Binary.Bits"},{"name":"shiftRightBy","comment":" Arithmetic right shift.\n\n -- ARI-RIGHTSHIFT 10010111 (decimal 151)\n -- = 11001011 (decimal 203)\n\n >>> [ 1, 0, 0, 1, 0, 1, 1, 1 ]\n ..> |> fromIntegers\n ..> |> shiftRightBy 1\n ..> |> toIntegers\n [ 1, 1, 0, 0, 1, 0, 1, 1 ]\n\n","type":"Basics.Int -> Binary.Bits -> Binary.Bits"},{"name":"shiftRightZfBy","comment":" Logical right shift.\n\n -- LOG-RIGHTSHIFT 10010111 (decimal 151)\n -- = 00001011 (decimal 11)\n\n >>> [ 0, 0, 0, 1, 0, 1, 1, 1 ]\n ..> |> fromIntegers\n ..> |> shiftRightZfBy 1\n ..> |> toIntegers\n [ 0, 0, 0, 0, 1, 0, 1, 1 ]\n\n","type":"Basics.Int -> Binary.Bits -> Binary.Bits"},{"name":"subtract","comment":" Subtract two sets of bits from each other.\n\n -- SUBTRACT 1011\n -- 11\n -- = 1010\n\n >>> subtract\n ..> (fromIntegers [ 1, 0, 1, 1 ])\n ..> (fromIntegers [ 1, 1 ])\n fromIntegers [ 1, 0, 0, 0 ]\n\n >>> subtract\n ..> (fromIntegers [ 1, 0, 0, 0, 1 ])\n ..> (fromIntegers [ 0, 0, 1, 0, 0 ])\n fromIntegers [ 0, 1, 1, 0, 1 ]\n\n","type":"Binary.Bits -> Binary.Bits -> Binary.Bits"},{"name":"toBooleans","comment":" Convert `Bits` to a list of booleans.\n\n >>> toBooleans <| fromHex \"8\"\n [ True, False, False, False ]\n\n","type":"Binary.Bits -> List.List Basics.Bool"},{"name":"toDecimal","comment":" Convert `Bits` to a decimal.\n\n >>> toDecimal <| fromIntegers [ 1, 0, 0, 0 ]\n 8\n\n","type":"Binary.Bits -> Basics.Int"},{"name":"toHex","comment":" Convert a list of binary numbers to a hex string.\n\n >>> toHex <| fromIntegers [ 1, 0, 0, 0 ]\n \"8\"\n\n","type":"Binary.Bits -> String.String"},{"name":"toIntegers","comment":" Convert `Bits` to a list of integers.\n\n >>> toIntegers <| fromHex \"8\"\n [ 1, 0, 0, 0 ]\n\n","type":"Binary.Bits -> List.List Basics.Int"},{"name":"toString","comment":" Convert `Bits` to a string.\n\n1. Splits the bits in chunks of the given number\n2. Each chunk is converted to a decimal (code point)\n3. Each code point is translated to a character\n4. The list of characters is converted to a string\n\nThe first argument determines how many bits\nare used per decimal value (ie. how large the chunks are).\n\n >>> \"0001F936\"\n ..> |> fromHex\n ..> |> toString 32\n \"🤶\"\n\n >>> \"616263\"\n ..> |> fromHex\n ..> |> toString 8\n \"abc\"\n\n","type":"Basics.Int -> Binary.Bits -> String.String"},{"name":"width","comment":" Get the amount of bits in a binary sequence.\n\n >>> fromIntegers [ 1, 0, 0, 0 ]\n ..> |> width\n 4\n\n","type":"Binary.Bits -> Basics.Int"},{"name":"xor","comment":" XOR operator.\n\n -- 0101 (decimal 5)\n -- XOR 0011 (decimal 3)\n -- = 0110 (decimal 6)\n\n >>> Binary.xor\n ..> (fromHex \"5\")\n ..> (fromHex \"3\")\n fromHex \"6\"\n\n","type":"Binary.Bits -> Binary.Bits -> Binary.Bits"}],"binops":[]}] \ No newline at end of file diff --git a/elm.json b/elm.json index e8cdc8b..963533d 100644 --- a/elm.json +++ b/elm.json @@ -3,7 +3,7 @@ "name": "icidasset/elm-binary", "summary": "Work with binary data.", "license": "MIT", - "version": "2.0.2", + "version": "2.1.0", "exposed-modules": [ "Binary" ], diff --git a/src/Binary.elm b/src/Binary.elm index 3c0eef1..aac9979 100644 --- a/src/Binary.elm +++ b/src/Binary.elm @@ -1,6 +1,6 @@ module Binary exposing ( Bits, empty - , fromHex, toHex, fromDecimal, toDecimal, fromIntegers, toIntegers, fromBooleans, toBooleans, fromString, toString + , fromHex, toHex, fromDecimal, toDecimal, fromIntegers, toIntegers, fromBooleans, toBooleans, fromString, fromStringAsUtf8, toString , and, or, xor, not , shiftLeftBy, shiftRightBy, shiftRightZfBy, rotateLeftBy, rotateRightBy , add, subtract @@ -14,7 +14,7 @@ module Binary exposing # Converters -@docs fromHex, toHex, fromDecimal, toDecimal, fromIntegers, toIntegers, fromBooleans, toBooleans, fromString, toString +@docs fromHex, toHex, fromDecimal, toDecimal, fromIntegers, toIntegers, fromBooleans, toBooleans, fromString, fromStringAsUtf8, toString # Bitwise Operators @@ -38,7 +38,6 @@ module Binary exposing -} -import Dict exposing (Dict) import List.Extra as List @@ -208,6 +207,11 @@ The resulting bits will represent the decimal value 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 ] @@ -243,6 +247,34 @@ fromString_ amountOfBitsPerCharacter char = |> unwrap +{-| 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" + +-} +fromStringAsUtf8 : String -> Bits +fromStringAsUtf8 string = + string + |> String.toList + |> List.concatMap unicodeCharToUtf8Bits + |> fromIntegers + + {-| Convert `Bits` to a string. 1. Splits the bits in chunks of the given number @@ -866,3 +898,76 @@ binaryToHexChar binary = _ -> Nothing + + + +-- TEXT ENCODING + + +{-| Translate a single unicode code-point to multiple utf-8 code-points. +-} +unicodeCharToUtf8Bits : Char -> List Int +unicodeCharToUtf8Bits char = + let + codepoint = + Char.toCode char + in + if codepoint < 128 then + -- 1-bit UTF-8 + codepoint + |> fromDecimal + |> ensureSize 8 + |> toIntegers + + else if codepoint < 2048 then + -- 2-bit UTF-8 + unicodeCharToUtf8Bits_ + [ [ 1, 1, 0 ] + , [ 1, 0 ] + ] + codepoint + + else if codepoint < 65536 then + -- 3-bit UTF-8 + unicodeCharToUtf8Bits_ + [ [ 1, 1, 1, 0 ] + , [ 1, 0 ] + , [ 1, 0 ] + ] + codepoint + + else + -- 4-bit UTF-8 + unicodeCharToUtf8Bits_ + [ [ 1, 1, 1, 1, 0 ] + , [ 1, 0 ] + , [ 1, 0 ] + , [ 1, 0 ] + ] + codepoint + + +unicodeCharToUtf8Bits_ : List (List Int) -> Int -> List Int +unicodeCharToUtf8Bits_ startingBits codepoint = + startingBits + |> List.foldr + (\start ( all, acc ) -> + let + takeAway = + 8 - List.length start + + ( end, rest ) = + List.splitAt takeAway acc + in + ( start ++ List.reverse end ++ all + , rest + ) + ) + ( [] + , codepoint + |> fromDecimal + |> ensureSize (8 * List.length startingBits) + |> toIntegers + |> List.reverse + ) + |> Tuple.first