Go to file
kayos@tcp.direct e759b4d601
Some checks failed
test / build (push) Has been cancelled
Fix: clarity on io.ReadWriter error separation
2024-06-16 00:29:58 -07:00
.github/workflows Feat: add CI test workflow 2024-06-11 03:29:32 -07:00
.gitignore init 2024-06-11 03:04:56 -07:00
go.mod init 2024-06-11 03:04:56 -07:00
go.sum init 2024-06-11 03:04:56 -07:00
LICENSE update README.md, add LICENSE 2024-06-11 03:28:05 -07:00
numbers_test.go Fix: typo that i thought about when trying to sleep 2024-06-16 00:20:21 -07:00
numbers.go Fix: clarity on io.ReadWriter error separation 2024-06-16 00:29:58 -07:00
README.md Fix: typo that i thought about when trying to sleep 2024-06-16 00:20:21 -07:00

didfmt

import "git.tcp.direct/kayos/didfmt"

Overview

package didfmt implements io.ReadWriteCloser and allows you to write streams of unformatted 11 digit (USA) phone numbers to it, and read formatted results separated by newline.

It is unnecessarily fast, but only supports 11 digit USA numbers. This makes it nearly a toy, but I've also made use of it in code that made it to staging environments, hilariously enough.

...Why?

This was something I made a while ago for a very specific purpose, and was a small package in a large module. Mostly for fun, I decided to extract the package and do some interesting things with Go's stdlib testing package.

Faster, or your green checkmark back.

This package, while doing the same thing as the following snippet, is:

  • faster
  • allocates less memory as a whole
  • has less memory allocation operations
fmt.Sprintf("+%s (%s) %s-%s", string(inbuf[0]), string(inbuf[1:4]), string(inbuf[5:8]), string(inbuf[6:10]))

guaranteed. otherwise the unit tests will literally fail :^)

Yes, I'm serious.

I'll let the output of go test -v speak for itself:

=== RUN   TestNumberFormatter
[...]
    numbers_test.go:137: input:
        12813308004
    numbers_test.go:151: output:
        +1 (281) 330-8004
    numbers_test.go:165: input:
        1281330800412813308004
    numbers_test.go:177: output:
        +1 (281) 330-8004
        +1 (281) 330-8004
=== RUN   TestNumberFormatter/writer/ridiculous
    numbers_test.go:194: input:
        "1 2 8 1))) MIKE JONES 33 oh (0 rather) eight 8 zero 0 zero 0 fo' 4"" :^)

        1555

        how's that one song go lmao its like 867 ... uh, 5309? i think?

        idfk
    numbers_test.go:207: output:
        +1 (281) 330-8004
        +1 (555) 867-5309
--- PASS: TestNumberFormatter (0.00s)
[...]
=== RUN   TestBenchmark
    numbers_test.go:273:

        --------------------------------------
        NumberFormatter.Next() benchmark
        --------------------------------------
        took 335 nanoseconds per phone number
        allocated memory 3 times per phone number
        allocated 72 bytes of memory per number
        it took 1.197248752s to format 3572934 phone numbers
        --------------------------------------

    numbers_test.go:273:

        --------------------------------------
        NumberFormatter.Read() benchmark
        --------------------------------------
        took 359 nanoseconds per phone number
        allocated memory 3 times per phone number
        allocated 72 bytes of memory per number
        it took 1.217125671s to format 3389002 phone numbers
        --------------------------------------

    numbers_test.go:273:

        --------------------------------------
        fmt.Sprintf() benchmark
        --------------------------------------
        took 518 nanoseconds per phone number
        allocated memory 9 times per phone number
        allocated 104 bytes of memory per number
        it took 1.213136762s to format 2338755 phone numbers
        --------------------------------------

    numbers_test.go:380:

        Read() is 30% faster than fmt.Sprintf(),
        makes 66% less allocations to allocate 30% less bytes.

    numbers_test.go:387:

        Next() is 35% faster than fmt.Sprintf(),
        makes 66% less allocations to allocate 30% less bytes.

--- PASS: TestBenchmark (4.85s)

Documentation

func FormatNumberBytes

func FormatNumberBytes(in []byte) (string, error)

FormatNumberBytes formats an input phone number byte slice in the format of +1 (123) 456-7890.

func FormatNumberString

func FormatNumberString(in string) (string, error)

FormatNumberString formats an input phone number string in the format of +1 (123) 456-7890.

type NumberFormatter

type NumberFormatter struct {
	*sync.Mutex
}

NumberFormatter is an optimized DID formatter that formats phone numbers.

func NewNumberFormatter

func NewNumberFormatter(source io.Reader) *NumberFormatter

NewNumberFormatter returns a new NumberFormatter.

func (*NumberFormatter) Close

func (nf *NumberFormatter) Close() error

Close closes the NumberFormatter and (if we can cast it to an [io.Closer]) the underlying source.

func (*NumberFormatter) Err

func (nf *NumberFormatter) Err() error

Err returns the error, if any, that occurred during the last call to Next.

func (*NumberFormatter) Next

func (nf *NumberFormatter) Next() string

Next returns the next formatted phone number or an empty string if there are no more numbers to format.

func (*NumberFormatter) Read

func (nf *NumberFormatter) Read(p []byte) (n int, err error)

Read implements io.Reader. It formats numbers from the data previously written, and then reads formatted phone numbers into the provided buffer.

func (*NumberFormatter) Reset

func (nf *NumberFormatter) Reset(source io.Reader)

Reset resets the NumberFormatter to use the provided io.Reader. Reset clears any errors, as well as any existing buffered data.

func (*NumberFormatter) Write

func (nf *NumberFormatter) Write(p []byte) (n int, err error)

Write implements io.Writer. It writes the provided bytes to the internal buffer.