nandi/rustnimpublic Fork
⑂ 5e05c89
Commits
⬇ Clone ▾
git clone https://git.rickub.com/nandi/rustnim.git
git clone ssh://git@rickub.com/nandi/rustnim.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

Download ZIP

Iterate a string's bytes

`for b in s.as_bytes()` is how a parser walks a string, and rustnim had
`as_bytes` only as a value -- in iterator position it was an unimplemented
adaptor. The bytes are a view of the string, not a copy, so this is an index
loop over it like any other slice.

`rsBytes` also takes the borrowed form. A `&str` parameter arrives as
`openArray[char]`, and its bytes are the same bytes.

tests/cases/077.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
nandithebull committed 2026-09-20T14:00:23-07:00 Browse files
5e05c89 parent: dee1a76
modified src/lower.rs +15 -0
@@ -5402,6 +5402,21 @@ impl Lowerer {
54025402 Iter::Filter { inner, param, body: Box::new(body) }
54035403 })
54045404 }
5405+ // `s.as_bytes()` in iterator position. The bytes are a
5406+ // view of the string, not a copy, so this is an index
5407+ // loop over it like any other slice.
5408+ "as_bytes" | "bytes" if m.args.is_empty() => {
5409+ let v = self.expr(&m.receiver)?;
5410+ let code = self.fresh("Bytes");
5411+ self.line(&format!("let {} = rsBytes({})", code, v.code));
5412+ Ok(Iter::Elems {
5413+ code: code.clone(),
5414+ off: "0".into(),
5415+ len: format!("{}.len", code),
5416+ elem: Some(Nim::Prim("uint8".into())),
5417+ mutable: false,
5418+ })
5419+ }
54055420 "enumerate" if m.args.is_empty() => {
54065421 Ok(Iter::Enumerate(Box::new(self.resolve_iter(&m.receiver)?)))
54075422 }
@@ -5402,6 +5402,21 @@ impl Lowerer {
5402 Iter::Filter { inner, param, body: Box::new(body) }5402 Iter::Filter { inner, param, body: Box::new(body) }
5403 })5403 })
5404 }5404 }
5405+ // `s.as_bytes()` in iterator position. The bytes are a
5406+ // view of the string, not a copy, so this is an index
5407+ // loop over it like any other slice.
5408+ "as_bytes" | "bytes" if m.args.is_empty() => {
5409+ let v = self.expr(&m.receiver)?;
5410+ let code = self.fresh("Bytes");
5411+ self.line(&format!("let {} = rsBytes({})", code, v.code));
5412+ Ok(Iter::Elems {
5413+ code: code.clone(),
5414+ off: "0".into(),
5415+ len: format!("{}.len", code),
5416+ elem: Some(Nim::Prim("uint8".into())),
5417+ mutable: false,
5418+ })
5419+ }
5405 "enumerate" if m.args.is_empty() => {5420 "enumerate" if m.args.is_empty() => {
5406 Ok(Iter::Enumerate(Box::new(self.resolve_iter(&m.receiver)?)))5421 Ok(Iter::Enumerate(Box::new(self.resolve_iter(&m.receiver)?)))
5407 }5422 }
modified src/prelude.nim +6 -0
@@ -304,6 +304,12 @@ proc rsDisplay*(x: openArray[char]): string =
304304
305305 proc rsDebug*(x: openArray[char]): string = rsDebug(rsDisplay(x))
306306
307+proc rsBytes*(s: openArray[char]): seq[uint8] =
308+ ## The borrowed form: a `&str` parameter arrives as `openArray[char]`, and
309+ ## its bytes are the same bytes.
310+ result = newSeq[uint8](s.len)
311+ for i in 0 ..< s.len: result[i] = uint8(s[i])
312+
307313 proc rsBytes*(s: string): seq[uint8] =
308314 ## Rust's `str::as_bytes` is a view of the UTF-8 encoding; Nim's `string` is
309315 ## already those bytes, so this is a reinterpretation, not a conversion.
@@ -304,6 +304,12 @@ proc rsDisplay*(x: openArray[char]): string =
304 304
305 proc rsDebug*(x: openArray[char]): string = rsDebug(rsDisplay(x))305 proc rsDebug*(x: openArray[char]): string = rsDebug(rsDisplay(x))
306 306
307+proc rsBytes*(s: openArray[char]): seq[uint8] =
308+ ## The borrowed form: a `&str` parameter arrives as `openArray[char]`, and
309+ ## its bytes are the same bytes.
310+ result = newSeq[uint8](s.len)
311+ for i in 0 ..< s.len: result[i] = uint8(s[i])
312+
307 proc rsBytes*(s: string): seq[uint8] =313 proc rsBytes*(s: string): seq[uint8] =
308 ## Rust's `str::as_bytes` is a view of the UTF-8 encoding; Nim's `string` is314 ## Rust's `str::as_bytes` is a view of the UTF-8 encoding; Nim's `string` is
309 ## already those bytes, so this is a reinterpretation, not a conversion.315 ## already those bytes, so this is a reinterpretation, not a conversion.
added tests/cases/077-bytes-iter.rs +26 -0
new file mode 100644
@@ -0,0 +1,26 @@
1+// `s.as_bytes()` in iterator position. The bytes are a view of the string,
2+// not a copy, so it is an index loop over it like any other slice.
3+fn checksum(s: &str) -> u32 {
4+ let mut t: u32 = 0;
5+ for b in s.as_bytes() {
6+ t += *b as u32;
7+ }
8+ t
9+}
10+
11+fn count_upper(s: &str) -> u32 {
12+ let mut n: u32 = 0;
13+ for (i, b) in s.as_bytes().iter().enumerate() {
14+ if *b >= 65 && *b <= 90 {
15+ n += 1 + i as u32;
16+ }
17+ }
18+ n
19+}
20+
21+fn main() {
22+ println!("{}", checksum("abc"));
23+ println!("{}", checksum(""));
24+ println!("{}", count_upper("aBcDe"));
25+ println!("{}", count_upper("xyz"));
26+}
new file mode 100644
@@ -0,0 +1,26 @@
1+// `s.as_bytes()` in iterator position. The bytes are a view of the string,
2+// not a copy, so it is an index loop over it like any other slice.
3+fn checksum(s: &str) -> u32 {
4+ let mut t: u32 = 0;
5+ for b in s.as_bytes() {
6+ t += *b as u32;
7+ }
8+ t
9+}
10+
11+fn count_upper(s: &str) -> u32 {
12+ let mut n: u32 = 0;
13+ for (i, b) in s.as_bytes().iter().enumerate() {
14+ if *b >= 65 && *b <= 90 {
15+ n += 1 + i as u32;
16+ }
17+ }
18+ n
19+}
20+
21+fn main() {
22+ println!("{}", checksum("abc"));
23+ println!("{}", checksum(""));
24+ println!("{}", count_upper("aBcDe"));
25+ println!("{}", count_upper("xyz"));
26+}