main.rs
rust · 61 lines · Exact bytes
Version & provenance · rust-codec-345ea0dc14f1
Recorded SHA-256 0220011c6d4165a9896dfa7b9b504b8b681572c30a6338e2d59c70274eb80243Rendered SHA-256 0220011c6d4165a9896dfa7b9b504b8b681572c30a6338e2d59c70274eb80243
Apache-2.0 original code; cozy-chess dependencies MIT License notes. Line links are stable within this snapshot. Exact Rust files match the build receipt and Elite codec identity. src/ paths are flattened only for source browsing; downloadable ZIP preserves original tree. README is a new public build guide.
1use std::io::{self,BufRead,Read,Write};
2use std::sync::mpsc::sync_channel;
3use chess_codec_prototype::{encode_san,decode_tokens,encode_movetext};
4
5fn line_result(line:&str)->String {
6 let fields:Vec<_>=line.trim_end_matches('\n').split('\t').collect();
7 if fields.len()!=3{return "ERR\tinvalid_protocol".into()}
8 if fields[0]=="PGN" {
9 if fields[1]!="-" {return "ERR\tnonstandard_start".into();}
10 return match encode_movetext(fields[2]) {
11 Ok((r,ending))=>format!("OK\t{}\t{}\t{}\t{}",r.uci.join(" "),r.tokens.iter().map(u8::to_string).collect::<Vec<_>>().join(","),r.fen,ending),
12 Err(e)=>format!("ERR\t{e}")
13 };
14 }
15 let fen=if fields[1]=="-" {None}else{Some(fields[1])};
16 let result=match fields[0] {
17 "SAN"=>encode_san(fields[2],fen),
18 "TOK"=>fields[2].split(',').map(str::parse::<u8>).collect::<Result<Vec<_>,_>>()
19 .map_err(|_|"invalid_token_integer".into()).and_then(|t|decode_tokens(&t,fen)),
20 _=>Err("invalid_mode".into())
21 };
22 match result {Ok(r)=>format!("OK\t{}\t{}\t{}",r.uci.join(" "),r.tokens.iter().map(u8::to_string).collect::<Vec<_>>().join(","),r.fen),
23 Err(e)=>format!("ERR\t{e}")}
24}
25fn main()->Result<(),Box<dyn std::error::Error>> {
26 let workers=std::env::args().nth(1).ok_or("workers required")?.parse::<usize>()?;
27 if !(1..=32).contains(&workers){return Err("workers must be1..32".into())}
28 let mut input=io::stdin().lock();let mut output=io::BufWriter::new(io::stdout().lock());
29 let (result_tx,result_rx)=sync_channel(4096);
30 let mut senders=Vec::new();let mut handles=Vec::new();
31 for _ in 0..workers {
32 let (tx,rx)=sync_channel::<(usize,String)>(16);senders.push(tx);
33 let result_tx=result_tx.clone();
34 handles.push(std::thread::spawn(move|| {
35 while let Ok((id,line))=rx.recv() {
36 if result_tx.send((id,line_result(&line))).is_err(){break;}
37 }
38 }));
39 }
40 drop(result_tx);
41 loop {
42 let mut block=Vec::new();
43 let mut block_bytes=0;
44 for _ in 0..4096 {
45 let mut line=String::new();
46 let read=(&mut input).take(1048577).read_line(&mut line)?;
47 if read>1048576{return Err("protocol record exceeds1MiB".into())}
48 if read==0 {break;} block_bytes+=read;block.push(line);
49 if block_bytes>=1024*1024 {break;}
50 }
51 if block.is_empty(){break;}
52 let mut results=vec![String::new();block.len()];
53 for (id,line) in block.into_iter().enumerate(){senders[id%workers].send((id,line))?;}
54 for _ in 0..results.len(){let (id,result)=result_rx.recv()?;results[id]=result;}
55 for result in results {writeln!(output,"{result}")?;}
56 output.flush()?;
57 }
58 drop(senders);for handle in handles {handle.join().map_err(|_|"worker panic")?;}
59 output.flush()?;Ok(())
60}
61