Add compact string encoding library
Description
Adds utils/PackedStringLib.sol - a library for efficiently encoding strings that are <=31 bytes.
- Encodes input strings by putting the length in the first byte and the body in the following 31 bytes.
- Decodes strings by clearing two words in memory (to ensure the string has leading and trailing zeroes) and then writing the packed form to the last byte of the length buffer (first word), which also places the right-padded body of the string where it needs to be.
Solidity's built-in mechanism for accessing storage strings is efficient when strings can be any size, but in practice most tend to be quite small and static. This means that all of the additional code for determining the type of string (single or multiple word), looping over words and hashing each index to get the slot, goes totally unused. Surprisingly, this can add up to several hundred (or even thousand!) bytes depending on your optimization settings, and can really eat into available contract space.
Below is a comparison of the simplest use-case (retrieving a contract's name) with packed vs. standard strings and constant/immutable vs. storage.

I tried to stick to the coding conventions as much as possible, but this file has a lot more comments than most - had a bit of an ADHD moment. @transmissions11 if you prefer to keep to the clean aesthetic I'm happy to remove them.
I'm also a little new to Forge, so I'd appreciate a second opinion on whether there are any gaps in the testing.
Checklist
Ensure you completed all of the steps below before submitting your pull request:
- [x] Ran
forge snapshot? - [x] Ran
npm run lint? - [x] Ran
forge test?