From 3e8bedb0c9fbfb15190e82b2323f66830423782c Mon Sep 17 00:00:00 2001 From: Chris Mounce Date: Wed, 18 Mar 2026 17:07:37 -0700 Subject: [PATCH] Clean up docs for Program enum, text functions --- src/text.rs | 16 ++++++++++------ src/world.rs | 31 ++++++++++++++++++++++++++----- 2 files changed, 36 insertions(+), 11 deletions(-) diff --git a/src/text.rs b/src/text.rs index a76b99d..7adbf39 100644 --- a/src/text.rs +++ b/src/text.rs @@ -3,7 +3,8 @@ use codepage_437::CP437_WINGDINGS; use super::errors::EncodeError; /// Serialize a multi-line code string for an object or a scroll. -/// Uses ZZT's convention of CR-terminated lines. +/// +/// Characters that do not have a CP437 equivalent will result in an [`EncodeError::EncodingError`]. pub fn encode_multiline(input: &str) -> Result, EncodeError> { input .chars() @@ -33,8 +34,11 @@ pub fn decode_multiline(input: &[u8]) -> String { .collect() } -/// Serialize a single-line string for a board title. -/// Newlines cannot be encoded because ZZT interprets them as dingbats (♪). +/// Serialize a single-line string, such as a board title. +/// +/// Newlines cannot be encoded because in single-line contexts, ZZT interprets that byte as a +/// dingbat, specifically the '♪' character. Passing a newline, or any non-CP437 character, will +/// result in an [`EncodeError::EncodingError`]. pub fn encode_oneline(input: &str) -> Result, EncodeError> { input .chars() @@ -46,7 +50,7 @@ pub fn encode_oneline(input: &str) -> Result, EncodeError> { .collect() } -/// Deserialize a board title. +/// Deserialize a single-line string, such as a board title. pub fn decode_oneline(input: &[u8]) -> String { input.iter().map(|&x| CP437_WINGDINGS.decode(x)).collect() } @@ -60,7 +64,7 @@ mod tests { encode_multiline(input).expect("Error in test") } - fn serialize_title(input: &str) -> Vec { + fn serialize_line(input: &str) -> Vec { encode_oneline(input).expect("Error in test") } @@ -73,7 +77,7 @@ mod tests { #[test] fn roundtrip_oneline() { let bytes: Vec = (0..=255).collect(); - assert_eq!(bytes, serialize_title(&decode_oneline(&bytes))) + assert_eq!(bytes, serialize_line(&decode_oneline(&bytes))) } #[test] diff --git a/src/world.rs b/src/world.rs index c5a21b8..6ac1af8 100644 --- a/src/world.rs +++ b/src/world.rs @@ -351,15 +351,36 @@ pub struct Tile { pub color: u8, } -/// A stat's ZZT-OOP program. +/// A stat's ZZT-OOP program text. /// -/// In ZZT, stats can either have their own code or bind to another stat's code. -/// This enum prevents invalid states where both are set. +/// Stats must either have their own program or bind to another stat's program. This is either-or: +/// in ZZT, it is impossible to represent a stat that has both (or neither). This enum models that +/// constraint. +/// +/// Internally, this is because ZZT uses a single `i16` like an enum discriminant. Zero or more +/// indicates the length of the program text, i.e., how many bytes follow the stat on disk. Negative +/// values are interpreted as negated bind indexes: -123 means no program text follows, and that the +/// stat instead shares code with the 123rd stat on the board. #[derive(Debug, Clone, PartialEq, Eq)] pub enum Program { - /// The stat owns its own code. + /// The stat has its own program code. + /// + /// This is the typical default for most stats. For stats that don't have or need a program, an + /// empty `String` is used. The text has a maximum of 32767 characters, though in ZZT 3.2 you + /// will encounter other limits before that. + /// + /// Despite the name, this has more to do with ZZT's behavior than with Rust ownership. Own(String), - /// The stat is bound to another stat (index into the stats list). + /// The stat is bound to the code at the given stat index. + /// + /// Bind indexes are 0-based, with the asterisk that zero is not representable due to how ZZT + /// encodes bind indexes. The smallest possible value is 1, which represents being bound to the + /// stat that comes immediately after the player. + /// + /// The largest representable bind index is 32768. zztff will successfully serialize this value, + /// though it's only useful as a curiosity and will likely crash ZZT: the index will definitely + /// be out of bounds because it is impossible to serialize a stat list that long without hitting + /// other limits in the file format. Indexes larger than that will result in an [`EncodeError`]. Bound(NonZero), }