Skip to content

Instantly share code, notes, and snippets.

@creachadair
creachadair / generic-string.md
Last active March 11, 2024 15:36
A cute trick with strings

Strings and Bytes: Together Again

Sometimes you want your Go function to accept either a string or a slice of bytes, at which point the user then has to convert whichever one they have to the version you chose:

func Process(s string) { /* … do stuff with s … */ }

// …
var someBytes = []byte(/* … */)
pkg.Process(string(someBytes))
@creachadair
creachadair / vm-shutdown.sh
Created March 2, 2024 16:24
Set or refresh a timed shutdown of a machine
#!/usr/bin/env bash
#
# Usage: shutdown.sh [--check|--cancel]
#
# Schedule a shutdown of the system at a time in the future.
# With --check, do not schedule a shutdown, just print the scheduled time.
# With --cancel, cancel a pending shutdown.
#
set -euo pipefail
@creachadair
creachadair / packed-length.md
Last active January 15, 2024 17:49
A self-framing packed binary format for unsigned integer lengths

Self-Framing Packed Binary Lengths

We describe a variable-width binary encoding format for unsigned integer lengths that handles values up to 1073741823 $(2^{30} - 1)$ and does not require complex bit manipulation to pack and unpack.

In summary: The input is encoded as little-endian, with the excess length of the encoding packed into the lowest-order 2 bits of the value. This makes the encoding self-framing, as the decoder can consume the first byte and immediately know how many additional bytes must be read to recover the original value. The only operations required are integer addition, multiplication, and division/remainder by powers of 2 (specificially, 4 and 256).

The algorithm below is described for 32-bit unsigned integers, but it can be extended trivially to 64-bit integers by using the lowest-order 3 bits instead of 2, or contracted to 16-bit integers using the lowest-order 1 bit.

A Go implementation

@creachadair
creachadair / gh-heading-anchors.md
Last active October 10, 2023 16:35
GitHub Heading Anchors and You: A Tale of Needless and Undocumented Complexity

GitHub renders Markdown in its UI according to the [GitHub Flavored Markdown (GFM)][gfm] spec. In addition, it adds generated link anchors for document headers. For example, a Markdown heading like:

## Fee Fie Fo Fum

is rendered with a link anchor of #fee-fie-fo-fum in the GitHub UI. Knowing this, you may wish to add links in other Markdown documents in your repository that point to those anchor targets. There are various descriptions floating around about how to do this, but all the ones I found contain subtle errors. This document attempts to clarify the rule.

Definitions

@creachadair
creachadair / options.md
Last active July 28, 2023 23:12
My current preferred option plumbing style in Go

Option Plumbing in Go

This gist outlines my current preferred library package organization style in Go. There are a few explanatory comments, but for the most part it's just an extended example.

// Package thing is named for the concept it implements.
package thing

// Thing is the principal type that implements the concept.
// Although this does stutter a little with the package name,
@creachadair
creachadair / pointer-construction.md
Last active July 26, 2023 14:00
Constructing pointers to type parameters in Go

Constructing Pointers to Type Parameters

I wanted to have a function that could construct a value satisfying an interface, do some setup on that value, and then pass the constructed value to some other operation. Schematically:

func doAThing(fn func(*Input) (Output, error)) (Output, error) {
    in := new(Input)
    in.Setup()
    return fn(in)
}
@creachadair
creachadair / type-parameter-iface.md
Created July 22, 2023 22:05
Checking type parameters for optional interface satisfaction in Go

Checking Type Parameters for Optional Interface Satisfaction

With Go generics, it is not permitted to check whether a value whose type comes from a type parameter satisfies some optional interface. For example, the following code will not compile (as of Go 1.20):

type Q interface{ Q() }

func G[T any](t T) {
	if q, ok := t.(Q); ok {
 q.Q()
@creachadair
creachadair / ws.sh
Last active February 15, 2024 16:55
A script to start and stop an AWS VM for development and testing
#!/bin/sh
#
# ws.sh: start and stop an EC2 VM
#
# Requires:
# - https://github.com/99designs/aws-vault
# - https://aws.amazon.com/cli/
#
# Usage:
# ws.sh start [--wait]
@creachadair
creachadair / mjpeg.md
Created April 12, 2023 05:54
MJPEG notes
@creachadair
creachadair / underlying.md
Last active March 26, 2023 17:04
Underlying types in Go generics

Use of Underlying Types in Go Generics

When specifying the type parameters for a generic structure in Go, you can use the notation ~T to mean "any type whose underlying structure is equivalent to T". For example, given:

func F[X ~string](x X) {}

the type parameter X can be instantiated with any type whose underlying representation is string. That includes string itself, of course, along with types like type Foo string which are based on it.