... This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
... If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.

(.require
 [library
  [lux (.except)
   ["$" documentation]
   [data
    [text (.only \n)
     ["%" \\injection]]
    [collection
     ["[0]" list (.use "[1]#[0]" monoid)]]]
   [meta
    [macro
     ["[0]" template]]]]]
 ["[0]" \\injection]
 ["[0]" \\projection]
 [\\library
  ["[0]" /]])

(`` (the \\projection
      (List $.Documentation)
      (let [specific (list ($.definition \\projection.size_8)
                           ($.definition \\projection.size_16)
                           ($.definition \\projection.size_32)
                           ($.definition \\projection.size_64)
                           ($.definition \\projection.bits_8)
                           ($.definition \\projection.bits_16)
                           ($.definition \\projection.bits_32)
                           ($.definition \\projection.bits_64)
                           ($.definition \\projection.natural)
                           ($.definition \\projection.integer)
                           ($.definition \\projection.revolution)
                           ($.definition \\projection.decimal)
                           ($.definition \\projection.invalid_tag)
                           ($.definition \\projection.or)
                           ($.definition \\projection.not_a_bit)
                           ($.definition \\projection.bit)
                           ($.definition \\projection.text)
                           ($.definition \\projection.maybe)
                           ($.definition \\projection.set_elements_are_not_unique)
                           ($.definition \\projection.symbol)
                           ($.definition \\projection.type)
                           ($.definition \\projection.location)
                           ($.definition \\projection.code)

                           ($.definition \\projection.segment
                             "Parses a chunk of data of a given size."
                             ($.example (' (segment size))))

                           (,, (template.with [<size> <name>]
                                 [($.definition <name>
                                    (%.message "Parses a block of data prefixed with a size that is " (%.natural <size>) " bytes long."))]

                                 [08 \\projection.binary_8]
                                 [16 \\projection.binary_16]
                                 [32 \\projection.binary_32]
                                 [64 \\projection.binary_64]
                                 ))

                           (,, (template.with [<size> <name>]
                                 [($.definition <name>
                                    (%.message "Parses a block of (UTF-8 encoded) text prefixed with a size that is " (%.natural <size>) " bytes long."))]

                                 [08 \\projection.utf8_8]
                                 [16 \\projection.utf8_16]
                                 [32 \\projection.utf8_32]
                                 [64 \\projection.utf8_64]
                                 ))

                           (,, (template.with [<size> <name>]
                                 [($.definition <name>
                                    (%.message "Parses a sequence of values prefixed with a size that is " (%.natural <size>) " bytes long."))]

                                 [08 \\projection.sequence_8]
                                 [16 \\projection.sequence_16]
                                 [32 \\projection.sequence_32]
                                 [64 \\projection.sequence_64]
                                 ))

                           ($.definition \\projection.list
                             "Parses an arbitrarily long list of values."
                             ($.example (' (list value))))

                           ($.definition \\projection.set
                             ""
                             ($.example (' (set hash value)))))]
        (list.partial ($.module \\projection._
                                "")

                      ($.definition \\projection.binary_was_not_fully_read)

                      ($.definition \\projection.Offset
                        "An offset for reading within binary data.")

                      ($.definition (\\projection.Projection it)
                        "A projection for raw binary data.")

                      ($.definition \\projection.value
                        "Runs a projection and checks that all the binary data was read by it."
                        ($.example (' (value projection input))))

                      ($.definition \\projection.end?
                        "Checks whether there is no more data to read.")

                      ($.definition \\projection.offset
                        "The current offset (i.e. how much data has been read).")

                      ($.definition \\projection.remaining
                        "How much of the data remains to be read.")

                      ($.definition \\projection.Size
                        "The size of a chunk of data within a binary array.")

                      ($.definition \\projection.rec
                        "Tie the knot for a recursive projection.")

                      ($.definition \\projection.any
                        "Does no parsing, and just returns a dummy value.")

                      specific
                      ))))

(the \\injection
  (List $.Documentation)
  (let [specific (list ($.definition \\injection.bits_8)
                       ($.definition \\injection.bits_16)
                       ($.definition \\injection.bits_32)
                       ($.definition \\injection.bits_64)
                       ($.definition \\injection.any)
                       ($.definition \\injection.bit)
                       ($.definition \\injection.natural)
                       ($.definition \\injection.integer)
                       ($.definition \\injection.revolution)
                       ($.definition \\injection.decimal)
                       ($.definition \\injection.binary_8)
                       ($.definition \\injection.binary_16)
                       ($.definition \\injection.binary_32)
                       ($.definition \\injection.binary_64)
                       ($.definition \\injection.utf8_8)
                       ($.definition \\injection.utf8_16)
                       ($.definition \\injection.utf8_32)
                       ($.definition \\injection.utf8_64)
                       ($.definition \\injection.text)
                       ($.definition \\injection.sequence_8)
                       ($.definition \\injection.sequence_16)
                       ($.definition \\injection.sequence_32)
                       ($.definition \\injection.sequence_64)
                       ($.definition \\injection.maybe)
                       ($.definition \\injection.list)
                       ($.definition \\injection.set)
                       ($.definition \\injection.symbol)
                       ($.definition \\injection.type)
                       ($.definition \\injection.location)
                       ($.definition \\injection.code)

                       ($.definition \\injection.segment
                         "Writes at most 'size' bytes of an input binary blob."
                         ($.example (' (segment size)))))]
    (list.partial ($.module \\injection._
                            "")
                  
                  ($.definition \\injection.monoid)

                  ($.definition \\injection.Mutation
                    "A mutation of binary data, tracking where in the data to transform.")

                  ($.definition \\injection.Specification
                    "A description of how to transform binary data.")

                  ($.definition \\injection.no_op
                    "A specification for empty binary data.")

                  ($.definition \\injection.instance
                    "Given a specification of how to construct binary data, yields a binary blob that matches it.")

                  ($.definition (\\injection.Injection it)
                    "An operation that knows how to write information into a binary blob.")

                  ($.definition \\injection.value
                    "Yields a binary blob with all the information written to it."
                    ($.example (' (value format value))))

                  ($.definition \\injection.or
                    ""
                    ($.example (' (or left right))))

                  ($.definition \\injection.and
                    ""
                    ($.example (' (and pre post))))

                  ($.definition \\injection.rec
                    "A combinator for recursive formats."
                    ($.example (' (rec body))))

                  specific
                  )))

(the .public documentation
  (List $.Documentation)
  (list.partial ($.module /._
                          "")

                ($.definition /.index_out_of_bounds)
                ($.definition /.slice_out_of_bounds)
                ($.definition /.size)
                ($.definition /.equivalence)
                ($.definition /.monoid)

                ($.definition /.Binary
                  "A binary BLOB of data.")

                ($.definition /.empty
                  "A fresh/empty binary BLOB of the specified size."
                  ($.example (' (empty size))))

                ($.definition /.mix
                  ""
                  ($.example (' (mix f init binary))))

                ($.definition /.bits_8
                  "Read 1 byte (8 bits) at the given index."
                  ($.example (' (bits_8 index binary))))

                ($.definition /.bits_16
                  "Read 2 bytes (16 bits) at the given index."
                  ($.example (' (bits_16 index binary))))

                ($.definition /.bits_32
                  "Read 4 bytes (32 bits) at the given index."
                  ($.example (' (bits_32 index binary))))

                ($.definition /.bits_64
                  "Read 8 bytes (64 bits) at the given index."
                  ($.example (' (bits_64 index binary))))

                ($.definition /.has_8!
                  "Write 1 byte (8 bits) at the given index."
                  ($.example (' (has_8! index value binary))))

                ($.definition /.has_16!
                  "Write 2 bytes (16 bits) at the given index."
                  ($.example (' (has_16! index value binary))))

                ($.definition /.has_32!
                  "Write 4 bytes (32 bits) at the given index."
                  ($.example (' (has_32! index value binary))))

                ($.definition /.has_64!
                  "Write 8 bytes (64 bits) at the given index."
                  ($.example (' (has_64! index value binary))))

                ($.definition /.copy!
                  "Mutates the target binary BLOB by copying bytes from the source BLOB to it."
                  ($.example (' (copy! bytes source_offset source target_offset target))))

                ($.definition /.slice
                  "Yields a subset of the binary BLOB, so long as the specified range is valid."
                  ($.example (' (slice offset length binary))))

                ($.definition /.after
                  "Yields a binary BLOB with at most the specified number of bytes removed."
                  ($.example (' (after bytes binary))))

                (all list#composite
                     ..\\injection
                     ..\\projection
                     )
                ))
