I ported http-date-rs to SWI-prolog as an exercise and the result was useful enough to be worth packaging.
RFC 9110 allows three date formats: IMF-fixdate, RFC 850 and asctime. The Rust version has a decoder (a Decoder struct with a position, expect/byte_at, a method per field) and a separate encoder built from format! calls. Two tables of month names pointing in opposite directions, and a fuzz target whose job is to catch them disagreeing.
The Prolog version is one grammar:
http_date(imf_fixdate, datetime(Day, Date, Time)) -->
day_name(Day, short), `, `, date1(Date), ` `, time(Time), ` GMT`.
decode/2 and encode/2 both call phrase/2 on it. The month table is seven facts read in whichever direction the caller needs.
Four things I liked:
- phrase/2 demands the whole list is consumed, which is the trailing-data check the Rust version does by hand
- digits//2 dispatches on var/1: parse when the value is unbound, format with leading zeros when it is bound. That is the only place reversibility needed help, because arithmetic only runs one way.
- The RFC 850 two-digit-year invariant needs no check. digits(2, 1994) fails, so the bad value is unrepresentable rather than rejected.
- The round trip test over every day and month pair are generated from the same tables the grammar reads. In rust - to do the same - I have had to separately define fuzz and property tests.
Lastly, the prolog version in significantly shorter - approximately about 20% of the rust version - while providing the same functionality.
Feedback welcome.
Bikal