ALL DEVLOGS

LOG 015

2026/09/11

★ Typed Identifiers

  • Publicly released the typed-ident crate alpha

  • Wrote and released a retrospective article on typed-ident

  • Found a design issue just after publishing (at least it's still alpha)

  • Started working on a fix for the design issue in question (#1)

typed-ident has been released!!

It’s only alpha, and I’m thankful for that, because just after publishing I noticed an issue.

The details are present in the GitHub issue that I filed, but the TL;DR is that the uncased types don’t enforce a consistent casing. So SnakeIdent doesn’t have to be either upper or lower case, it can be a mixture of cases.

I knew that this was the case, and originally I had convinced myself that it made sense. But now that I have the crate published, I don’t feel that way any longer. So I’m trying to fix it so that there’s a more strict stance on this.

I’ll still provide the mixed-case variants, they just may be named differently.

LOG 014

2026/09/04

★ Typed Identifiers

  • Fixed a design issue found during documentation.

  • Finished cleaning up benchmarks, examples, and rough unit tests.

  • Fell ill again in the middle of the week, so I'll publish next week.

I originally had a trip planned for this upcoming week, but I’ll have to cancel it and move it to another date.

I suppose the upside is I’ll be able to release this crate next week, instead of having to wait until returning from my trip. I’m going to finish recovering and then sometime early next week I’ll finally publish this thing.

Next week I’ll write a little retrospective too, that’ll be my article for the month.

LOG 013

2026/08/28

★ Typed Identifiers

  • Fully documented the remainder of the crate.

  • Created benchmarks using Criterion, and fixed some optimization issues.

  • Cleaned up the implementation a bit more, and some small rename operations.

  • Cleaning up the tests and ensuring decent test coverage for the initial release.

  • Fixed a small design issue with the identifier conversion traits.

I’m basically done, just cleaning up testing and documentation at this point.

There’s certainly more that could be done, but I think I want to get a 0.0.1 release out there, that way others can actually see what I’m working on (as opposed to me just talking about it in devlog updates).

I think it’ll release sometime next week - please look forward to it!

LOG 012

2026/08/21

★ Typed Identifiers

  • Fully documented the syntax and core modules.

  • Cleaned up various marker traits (SubsetOf, SingleCharGraphemes, etc).

  • Cleaned up the trait interface, and finalized the names for all the types.

  • Added an optional Strict profile, which hardens the enforcement of identifier formats.

  • Added more doctests, specifically around SubsetOf, to ensure things are working properly.

The API has been finalized!

I might change around some things (for instance, I’m currently debating if I want to put the syntax module under core), but for the most part it’s complete - just needs more documentation.

It changed a tiny bit from the last time I posted an example, so let’s take another look:

use crate::syntax::{boundary, delimiter, profile};
use crate::{Conversion, Ident, Chunk};

// A lower_snake_case identifier using the Unicode XID profile.
type LowerSnakeIdent = Ident<
    boundary::None,
    delimiter::LowLine,
    profile::Lower<profile::Unicode>,
>;

// Only allows lower_snake identifiers.
let ident = LowerSnakeIdent::new("example_snake")?;
assert!(LowerSnakeIdent::new("example-kebab").is_err());
assert!(LowerSnakeIdent::new("exampleCamel").is_err());

// You can easily extract segments of the identifier.
// Prints:
// * Chunk(Chunk("example"))
// * Delimiter(LowLine)
// * Chunk(Chunk("snake"))
println!("{ident} segments:");
for segment in ident.segments() {
    println!("* {segment:?}");
}

// You can also easily convert to other identifiers.
//
// The type here is `IdentBuf<Grapheme, LowLine, UpperCamel<Unicode>>`,
// but you can test against strings (`PartialEq` works against `&str`).
assert_eq!(ident.to_upper_camel()?, "ExampleSnake");

LOG 011

2026/08/14

★ Prototyping

  • Continued prototyping the major project I'm working on.

  • Experimented with some new ideas with traits that I think will improve the API.

  • A little work on typed identifiers, but mostly adding tests and documentation.

  • A little bit of deduplication work, moving common impls into declarative macros.

I don’t feel at liberty to share the main project I’m prototyping, still. But I can give you all a little sneak peek at how testing is done for the typed identifiers crate!

I’m pretty proud of how it works:

  • I have some files that dictate certain valid and invalid identifiers.
  • At runtime, the data is expanded in a stress integration test.
  • Each “test identifier” is visited, and based on the data, we attempt different operations, and validate against the test data.

Here’s an example for what this test data looks like (not actually in YAML format, just shown that way for example):

- name: "CaféPatron"
  kebab: true
  snake: true
  camel: true
  upper_camel: true
  segments:
  - !Chunk "Café"
  - !Boundary Camel
  - !Boundary Hat
  - !Chunk "Patron"

This entry says:

  1. There’s a valid identifier that can parse as mixed-case kebab, mixed-case snake, mixed-case camel, or upper-camel.
  2. Based on how the identifier is configured to respect chunk boundaries, it may or may not break apart Café from Patron (if CAMEL or HAT boundary options are enabled, specifically).
  3. Tests segmentation using all combinations of options, and ensures that they return ["CaféPatron"] or ["Café", "Patron"] as expected.
  4. Tests that case conversion works and respects chunk boundaries (e.g., when converting to another case, we have the same number of chunks, though they may now be slightly reformatted).

It also validates some inverse properties. For example, we cannot parse this as LowerSnakeIdent (according to the data), so we will validate that.

LOG 010

2026/08/07

★ Typed Identifiers

  • Continued experimenting with the typed identifiers API.

  • Refactored and deduped the various part types (Fragment, Word, Segment).

  • Created a Case trait to dedupe how we reformat character profiles.

  • Finished adding functionality to convert between different identifiers via the ConvertCase trait.

  • Started adding comprehensive integration tests to validate the functionality.

I thought this would be an easy and quick crate, and I’ve grossly underestimated how complicated generalized typed identifiers are.

I’m still not done with this, and it’s still not ready to share. But I can show you what it looks like currently (note: crate is the stand-in for the final crate name, which is currently undecided):

use crate::{casing, delimiter, profile, Ident};

// A lower_snake_case identifier using the Unicode XID profile.
type LowerSnakeIdent = Ident<
    casing::Lower,
    delimiter::LowLine,
    profile::Unicode,
>;

// Only allows lower_snake identifiers.
let ident = LowerSnakeIdent::new("example_snake")?;
assert!(LowerSnakeIdent::new("example-kebab").is_err());
assert!(LowerSnakeIdent::new("exampleCamel").is_err());

// You can easily extract segments of the identifier.
// Prints:
// * Word(Word("example"))
// * Delimiter(LowLine)
// * Word(Word("snake"))
println!("{ident} segments:");
for segment in ident.segments() {
    println!("* {segment:?}");
}

// You can also easily convert to other identifiers.
//
// The type here is `IdentBuf<UpperCamel, LowLine, Unicode>`,
// but you can test against strings (`PartialEq` works against `&str`).
assert_eq!(ident.to_upper_camel()?, "ExampleSnake");

LOG 009

2026/07/31

★ Typed Identifiers

  • Continued experimenting with the typed identifiers API.

  • Created a Profile trait for allowing users to configure the allowable character profile.

  • Created a Delimiter trait for allowing users to configure the allowable identifier delimiters.

  • Added some default profiles (unicode & ascii), as well as delimiters (hyphen minus, low bar, etc).

  • Documented the parts types and added doc tests where reasonable.

It’s taking a bit longer than I’d like to finish this typed identifiers crate, but I’m pretty happy with the direction it’s heading. I know that if I don’t follow this through now, I’ll have trouble following it through in the future.

I will give it another week. It’s not the most exciting project to release, but I’m happy with the direction it’s heading.

LOG 008

2026/07/24

★ Typed Identifiers

  • Split some of the utility functions I had into a helper crate for identifier parsing.

  • Added the ability to split identifiers into parts (fragments, segments, words, etc).

  • Added more functionality so that I can turn it into a more feature-complete crate (trimming, splitting, appending, etc).

  • Documented the current functionality and added unit tests for everything.

This crate is to have typed identifiers that I can work with in Rust, and for easily and safely converting cases. The main thing it does differently from similar libraries is that it actually has types that exist for the various identifier formats (LowerCamelIdentifier, UpperSnakeIdentifier, etc) instead of just having conversion functions.

This is needed for some future projects I have.

LOG 007

2026/07/17

★ Prototyping

  • Continued prototyping the major project I'm working on.

  • Starting to break the project up into sub-projects that I will release as helper crates.

  • Some slight cleanup of the articles that I've written so far.

I’m changing when I publish the monthly articles - instead of publishing them at the end of the month, I’m going to start publishing them on the first Monday of the month. This is so that the articles don’t intersect with the weekly devlogs, and because I think that most people probably aren’t reading technical articles over the weekend.

This means the next article will be on August 3rd - please look forward to it!

LOG 006

2026/07/10

★ Recovering From Illness

  • I was sick all week... Take care and stay healthy!

LOG 005

2026/07/03

★ Site Generator

  • General improvements to the site; canonicalized redirects, added aria support, better image handling, JPEG-XL support, inlining critical JS, deferred non-critical JS, user's default theme preference taken into account.

  • Improved the articles page to have better style, sticky headings, anchor link support, better word counting, reading time estimates.

  • Updated cache busting to use file hashes instead of modified times (that felt cleaner to me).

  • Fixed a bug where cached content was not properly marked as immutable in the response header.

  • Added proper support for article tags (with a tags page to view similar articles).

  • Started writing the next article I plan on publishing (not finished yet).

I didn’t want to work on this more, but it’s hard to look at a list of future improvements and not want to work to fix them now. I feel pretty happy with this update, despite not initially wanting to do it!

LOG 004

2026/06/26

★ Site Generator

  • Changed how static asset cache busting was done (the original method did not work on all browsers).

  • Added the ability to generate different sized and format images for efficient image presentation.

  • Added support for articles, as well as article selection (different from devlogs formatting).

  • Fixed some bugs where the site wasn't presenting properly (weird CSS, etc).

There’s definitely more to do here, but I’m really getting annoyed with how much time I’m spending on this website. I’m hoping this week will be the last time I have to spend significant effort on it.

LOG 003

2026/06/19

★ Prototyping

  • Spent most of my time working on a prototype for a project that I'm getting off the ground.

  • Added open graph and meta elements to the site to make it present clearer on social media.

  • Some small bug fixes and improvements to the website (colors, layouts, organization, etc).

  • Backend site generator improvements (code cleanup and logic deduplication).

I made an invasive change to the devlogs. If you were subscribed to the RSS feed, the old devlogs may register as new again (sorry about that). I’ll try to avoid that in the future, but it felt like a necessary change.

LOG 002

2026/06/12

★ Static Site Generator

  • Many bugs on the site have been ironed out.

  • Populated the "Home" and "About" page.

  • Wrote an article for the end of the month (to test article formatting).

  • Published the website for the first time!

I’m sure I’ll find little bugs here and there - but this website is not where I want to be spending the majority of my time. I’d much rather spend it on actual software project.

LOG 001

2026/06/05

★ Static Site Generator

  • The site generator is working, but it's not quite ready for production yet.

  • Lots of fundamental features are present (cache busting, header, devlogs, theme selection, etc.)

  • Did a bit of work on the prototype for the first major software project I'll be releasing.

I originally planned on having the site live by this date, but I’d rather hold off a while longer so that I can properly test it. Over the next week I’m going to continue working on the site, as well as begin drafting my first long-form article that I’ll post at the end of the month.