From d515b024246f0f3ae6ec9613c11e22c5de130050 Mon Sep 17 00:00:00 2001 From: Matthew Butterick Date: Sun, 28 Apr 2019 16:26:14 -0700 Subject: [PATCH] doc strings --- .../xenomorph/scribblings/xenomorph.scrbl | 185 +++++++++++++++++- xenomorph/xenomorph/string.rkt | 39 +++- 2 files changed, 210 insertions(+), 14 deletions(-) diff --git a/xenomorph/xenomorph/scribblings/xenomorph.scrbl b/xenomorph/xenomorph/scribblings/xenomorph.scrbl index e4ec3a75..f9896aa7 100644 --- a/xenomorph/xenomorph/scribblings/xenomorph.scrbl +++ b/xenomorph/xenomorph/scribblings/xenomorph.scrbl @@ -174,7 +174,7 @@ For those familiar with programming-language lingo, an encoding somewhat resembl (xenomorphic? [x any/c]) boolean?]{ -Predicate for whether @racket[x] is an object of type @racket[x:base%]. +Whether @racket[x] is an object of type @racket[x:base%]. } @defproc[ @@ -308,7 +308,7 @@ Base class for integer formats. Use @racket[x:int] to conveniently instantiate n (x:int? [x any/c]) boolean?]{ -Predicate for whether @racket[x] is an object of type @racket[x:int%]. +Whether @racket[x] is an object of type @racket[x:int%]. } @defproc[ @@ -387,7 +387,7 @@ Base class for floating-point number formats. By convention, all floats are sign (x:float? [x any/c]) boolean?]{ -Predicate for whether @racket[x] is an object of type @racket[x:float%]. +Whether @racket[x] is an object of type @racket[x:float%]. } @defproc[ @@ -449,7 +449,7 @@ Create class instance that represents a fixed-point number format @racket[size] (x:fixed? [x any/c]) boolean?]{ -Predicate for whether @racket[x] is an object of type @racket[x:fixed%]. +Whether @racket[x] is an object of type @racket[x:fixed%]. } @defproc[ @@ -498,6 +498,73 @@ The common 32-bit fixed-point number types with 4 bits of precision. They differ @defmodule[xenomorph/string] +@defproc[ +(supported-encoding? +[x any/c]) +boolean?]{ +Whether @racket[x] represents a supported encoding: either @racket['ascii] or @racket['utf8]. +} + +@defclass[x:string% x:base% ()]{ +Base class for string formats. Use @racket[x:string] to conveniently instantiate new string formats. + +@defconstructor[ +([len length-resolvable?] +[encoding supported-encoding?])]{ +Create class instance that represents a string format of length @racket[len]. If @racket[len] is an integer, the string is fixed at that length, otherwise it can be any length. +} + +@defmethod[ +#:mode extend +(x:decode +[input-port input-port?] +[parent (or/c xenomorphic? #false)]) +string?]{ +Returns a @tech{string}. +} + +@defmethod[ +#:mode extend +(x:encode +[val any/c] +[input-port input-port?] +[parent (or/c xenomorphic? #false)]) +bytes?]{ +Take a @racket[val], converts it to a string if needed, and encode it as a @tech{byte string}. If @racket[_len] is a @racket[xenomorphic?] object, the length is encoded at the beginning of the string using that object as the encoder. +} + +} + +@defproc[ +(x:string? +[x any/c]) +boolean?]{ +Whether @racket[x] is an object of type @racket[x:string%]. +} + +@defproc[ +(x:string +[len-arg (or/c length-resolvable? #false) #false] +[enc-arg (or/c supported-encoding? #false) #false] +[#:length len-kw (or/c length-resolvable? #false) #false] +[#:encoding enc-kw (or/c supported-encoding? #false) #false] +[#:pre-encode pre-encode-proc (or/c (any/c . -> . any/c) #false) #false] +[#:post-decode post-decode-proc (or/c (any/c . -> . any/c) #false) #false] +[#:base-class base-class (λ (c) (subclass? c x:string%)) x:string%] +) +x:string?]{ +Generate an instance of @racket[x:string%] (or a subclass of @racket[x:string%]) with certain optional attributes. + +@racket[len-arg] or @racket[len-kw] (whichever is provided, though @racket[len-kw] takes precedence) determines the length of the string. If this argument is an integer, the string is limited to that length. If it's another value, the string has variable length. + +@racket[enc-arg] or @racket[enc-kw] (whichever is provided, though @racket[enc-kw] takes precedence) determines the encoding of the string. See also @racket[supported-encoding?] + +@racket[pre-encode-proc] and @racket[post-decode-proc] control the pre-encoding and post-decodeing procedures, respectively. + +@racket[base-class] controls the class used for instantiation of the new object. +} + + @subsection{Lists} @@ -510,15 +577,35 @@ Base class for list formats. Use @racket[x:list] to conveniently instantiate new ([type xenomorphic?] [len length-resolvable?] [count-bytes? boolean?])]{ -Create class instance that represents a list format with elements of type @racket[type]. If @racket[len] is @racket[#false], the list can be any length, otherwise it is fixed at the resolved value of @racket[len]. +Create class instance that represents a list format with elements of type @racket[type]. If @racket[len] is an integer, the list is fixed at that length, otherwise it can be any length. } + +@defmethod[ +#:mode extend +(x:decode +[input-port input-port?] +[parent (or/c xenomorphic? #false)]) +list?]{ +Returns a @tech{list} of values whose length is @racket[_len] and where each value is @racket[_type]. +} + +@defmethod[ +#:mode extend +(x:encode +[seq sequence?] +[input-port input-port?] +[parent (or/c xenomorphic? #false)]) +bytes?]{ +Take a @tech{sequence} @racket[seq] and encode it as a @tech{byte string}. +} + } @defproc[ (x:list? [x any/c]) boolean?]{ -Predicate for whether @racket[x] is an object of type @racket[x:list%]. +Whether @racket[x] is an object of type @racket[x:list%]. } @defproc[ @@ -549,21 +636,41 @@ Generate an instance of @racket[x:list%] (or a subclass of @racket[x:list%]) wit @defmodule[xenomorph/stream] @defclass[x:stream% x:base% ()]{ -Base class for list formats. Use @racket[x:stream] to conveniently instantiate new list formats. +Base class for stream formats. Use @racket[x:stream] to conveniently instantiate new stream formats. @defconstructor[ ([type xenomorphic?] [len length-resolvable?] [count-bytes? boolean?])]{ -Create class instance that represents a list format with elements of type @racket[type]. If @racket[len] is @racket[#false], the list can be any length, otherwise it is fixed at the resolved value of @racket[len]. +Create class instance that represents a stream format with elements of type @racket[type]. If @racket[len] is an integer, the stream is fixed at that length, otherwise it can be any length. } + +@defmethod[ +#:mode extend +(x:decode +[input-port input-port?] +[parent (or/c xenomorphic? #false)]) +stream?]{ +Returns a @tech{stream} of values whose length is @racket[_len] and where each value is @racket[_type]. +} + +@defmethod[ +#:mode extend +(x:encode +[seq sequence?] +[input-port input-port?] +[parent (or/c xenomorphic? #false)]) +bytes?]{ +Take a @tech{sequence} @racket[seq] and encode it as a @tech{byte string}. +} + } @defproc[ (x:stream? [x any/c]) boolean?]{ -Predicate for whether @racket[x] is an object of type @racket[x:stream%]. +Whether @racket[x] is an object of type @racket[x:stream%]. } @defproc[ @@ -592,6 +699,66 @@ Generate an instance of @racket[x:stream%] (or a subclass of @racket[x:stream%]) @defmodule[xenomorph/vector] +@defclass[x:vector% x:base% ()]{ +Base class for vector formats. Use @racket[x:vector] to conveniently instantiate new vector formats. + +@defconstructor[ +([type xenomorphic?] +[len length-resolvable?] +[count-bytes? boolean?])]{ +Create class instance that represents a vector format with elements of type @racket[type]. If @racket[len] is an integer, the vector is fixed at that length, otherwise it can be any length. +} + +@defmethod[ +#:mode extend +(x:decode +[input-port input-port?] +[parent (or/c xenomorphic? #false)]) +vector?]{ +Returns a @tech{vector} of values whose length is @racket[_len] and where each value is @racket[_type]. +} + +@defmethod[ +#:mode extend +(x:encode +[seq sequence?] +[input-port input-port?] +[parent (or/c xenomorphic? #false)]) +bytes?]{ +Take a @tech{sequence} @racket[seq] and encode it as a @tech{byte string}. +} + +} + +@defproc[ +(x:vector? +[x any/c]) +boolean?]{ +Whether @racket[x] is an object of type @racket[x:vector%]. +} + +@defproc[ +(x:vector +[type-arg (or/c xenomorphic? #false) #false] +[len-arg (or/c length-resolvable? #false) #false] +[#:type type-kw (or/c xenomorphic? #false) #false] +[#:length len-kw (or/c length-resolvable? #false) #false] +[#:pre-encode pre-encode-proc (or/c (any/c . -> . any/c) #false) #false] +[#:post-decode post-decode-proc (or/c (any/c . -> . any/c) #false) #false] +[#:base-class base-class (λ (c) (subclass? c x:vector%)) x:vector%] +) +x:vector?]{ +Generate an instance of @racket[x:vector%] (or a subclass of @racket[x:vector%]) with certain optional attributes. + +@racket[type-arg] or @racket[type-kw] (whichever is provided, though @racket[type-kw] takes precedence) determines the type of the elements in the list. + +@racket[len-arg] or @racket[len-kw] (whichever is provided, though @racket[len-kw] takes precedence) determines the length of the list. This can be an ordinary integer, but it can also be any value that is @racket[length-resolvable?]. + +@racket[pre-encode-proc] and @racket[post-decode-proc] control the pre-encoding and post-decodeing procedures, respectively. + +@racket[base-class] controls the class used for instantiation of the new object. +} + @subsection{Structs} diff --git a/xenomorph/xenomorph/string.rkt b/xenomorph/xenomorph/string.rkt index baddf6e7..83849152 100644 --- a/xenomorph/xenomorph/string.rkt +++ b/xenomorph/xenomorph/string.rkt @@ -1,5 +1,10 @@ #lang racket/base -(require racket/class racket/match "base.rkt" "util.rkt" "number.rkt") +(require racket/class + racket/match + racket/contract + "base.rkt" + "util.rkt" + "number.rkt") (provide (all-defined-out)) #| @@ -28,6 +33,9 @@ https://github.com/mbutterick/restructure/blob/master/src/String.coffee (define (bytes-left-in-port? port) (not (eof-object? (peek-byte port)))) +(define (supported-encoding? x) + (and (symbol? x) (memq x supported-encodings))) + (define x:string% (class x:base% (super-new) @@ -35,8 +43,8 @@ https://github.com/mbutterick/restructure/blob/master/src/String.coffee (unless (length-resolvable? @len) (raise-argument-error 'xstring "length-resolvable?" @len)) - (unless (or (procedure? @encoding) (memq @encoding supported-encodings)) - (raise-argument-error 'xstring (format "procedure or member of ~v" supported-encodings) @encoding)) + (unless (or (procedure? @encoding) (supported-encoding? @encoding)) + (raise-argument-error 'x:string (format "procedure or member of ~v" supported-encodings) @encoding)) (define/augment (x:decode port parent) (define len (or (resolve-length @len port parent) (count-nonzero-chars port))) @@ -80,12 +88,33 @@ https://github.com/mbutterick/restructure/blob/master/src/String.coffee [else (resolve-length @len #f parent)])))) (define supported-encodings '(ascii utf8)) -(define (x:string [len-arg #f] [enc-arg #f] + +(define (x:string? x) (is-a? x x:string%)) + +(define/contract (x:string + [len-arg #f] + [enc-arg #f] #:length [len-kwarg #f] #:encoding [enc-kwarg #f] #:pre-encode [pre-proc #f] #:post-decode [post-proc #f] #:base-class [base-class x:string%]) + (() + ((or/c length-resolvable? #false) + (or/c supported-encoding? #false) + #:length (or/c length-resolvable? #false) + #:encoding (or/c supported-encoding? #false) + #:pre-encode (or/c (any/c . -> . any/c) #false) + #:post-decode (or/c (any/c . -> . any/c) #false) + #:base-class (λ (c) (subclass? c x:string%))) + . ->* . + x:string?) (define len (or len-arg len-kwarg)) + (unless (length-resolvable? len) + (raise-argument-error 'x:string "resolvable length" len)) (define encoding (or enc-arg enc-kwarg 'ascii)) - (new (generate-subclass base-class pre-proc post-proc) [len len] [encoding encoding])) + (unless (supported-encoding? encoding) + (raise-argument-error 'x:string "valid encoding value" encoding)) + (new (generate-subclass base-class pre-proc post-proc) + [len len] + [encoding encoding]))