LittlePlyResearch notebook

main.rs

rust · 61 lines · Exact bytes

Line 1 ↗
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