Skip to content

Commit b097388

Browse files
authored
Merge pull request #89 from silicon-heaven/cq
Cq
2 parents 5e40d72 + 435d136 commit b097388

6 files changed

Lines changed: 399 additions & 24 deletions

File tree

.github/workflows/rust.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ jobs:
4747
run: |
4848
mkdir -p ${{github.workspace}}/install
4949
export RUSTFLAGS="-A mismatched_lifetime_syntaxes"
50-
FEATURES="cp2cp,serde"
50+
FEATURES="cq,cp2cp,serde"
5151
if rustup default | grep nightly; then
5252
FEATURES+=",specialization"
5353
fi
@@ -99,7 +99,7 @@ jobs:
9999
uses: silicon-heaven/rust-pycobertura-action@v4.0.1
100100
with:
101101
project_name: libshvproto
102-
cargo_test_arguments: --features cp2cp,serde
102+
cargo_test_arguments: --features cq,cp2cp,serde
103103

104104
check-version-bump:
105105
name: Check version bump

Cargo.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ name = "shvproto"
55
description = "Rust implementation of the SHV protocol"
66
license = "MIT"
77
repository = "https://github.com/silicon-heaven/libshvproto-rs"
8-
version = "3.6.33"
8+
version = "4.0.0"
99
edition = "2024"
1010

1111
[dependencies]
@@ -16,6 +16,9 @@ hex = "0.4"
1616
clap = { version = "4.5", features = ["derive"] }
1717
simple_logger = { version = "5.0", features = ["stderr"], optional = true }
1818
serde = { version = "1.0.219", features = ["derive"], optional = true }
19+
jaq-all = { git = "https://github.com/01mf02/jaq", tag = "v3.0.0-beta", optional = true }
20+
# FIXME: remove this after jaq support is complete
21+
fn_name = "0.1.0"
1922

2023
[dev-dependencies]
2124
assert_cmd = "2.0"
@@ -25,6 +28,7 @@ shvproto = { path = ".", features = ["cp2cp"] }
2528
[features]
2629
cp2cp = ["dep:simple_logger"]
2730
serde = ["dep:serde"]
31+
cq = ["dep:jaq-all"]
2832

2933
# Enables feature `min_specialization` of nightly compiler and provides
3034
# special `impl From<Collection<RpcValue>> for RpcValue` to just move

src/bin/cp2cp.rs

Lines changed: 61 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ use std::io::{stdout, BufRead, BufReader, BufWriter};
1010
use std::path::PathBuf;
1111
use std::{fs, io, process};
1212

13+
#[cfg(feature = "cq")]
14+
use jaq_all::{jaq_core::{Ctx, Vars, data::JustLut}, jaq_std};
15+
1316
#[derive(Parser, Debug)]
1417
#[structopt(name = "cp2cp", version = env!("CARGO_PKG_VERSION"), author = env!("CARGO_PKG_AUTHORS"), about = "ChainPack to Cpon and back utility")]
1518
struct Cli {
@@ -30,13 +33,18 @@ struct Cli {
3033
/// File to process
3134
#[arg(value_name = "FILE")]
3235
file: Option<PathBuf>,
36+
/// Run cq with this filter.
37+
#[cfg(feature = "cq")]
38+
#[arg(long = "cq")]
39+
cq_filter: Option<String>,
3340
}
3441

3542
const CODE_SUCCESS: i32 = 0;
3643
const CODE_READ_ERROR: i32 = 1;
3744
const CODE_NOT_ENOUGH_DATA: i32 = 2;
3845
const CODE_WRITE_ERROR: i32 = 4;
39-
46+
#[cfg(feature = "cq")]
47+
const CODE_UNEXPECTED_ERROR: i32 = 5;
4048
struct ChainPackRpcBlockResult {
4149
block_length: Option<usize>,
4250
frame_length: Option<u64>,
@@ -138,7 +146,7 @@ fn main() {
138146
Some(filename) => Box::new(BufReader::new(fs::File::open(filename).unwrap())),
139147
};
140148

141-
let res = if opts.cpon_input {
149+
let read_result = if opts.cpon_input {
142150
let mut rd = CponReader::new(&mut reader);
143151
rd.read()
144152
} else if opts.chainpack_rpc_block {
@@ -147,31 +155,63 @@ fn main() {
147155
let mut rd = ChainPackReader::new(&mut reader);
148156
rd.read()
149157
};
150-
let rv = match res {
158+
159+
let input_value = match read_result {
151160
Err(e) => {
152161
eprintln!("Parse input error: {:?}", e);
153162
process::exit(CODE_READ_ERROR);
154163
}
155164
Ok(rv) => rv,
156165
};
157-
let mut writer = BufWriter::new(stdout());
158-
let res = if opts.chainpack_output {
159-
let mut wr = ChainPackWriter::new(&mut writer);
160-
wr.write(&rv)
166+
167+
#[cfg(feature = "cq")]
168+
let output_values = if let Some(filter) = opts.cq_filter {
169+
let filter = match jaq_all::compile_with(&filter, jaq_std::defs(), jaq_std::funs(), &[]) {
170+
Ok(filter) => filter,
171+
Err(error) => {
172+
eprintln!("Failed to parse cq filter: {error:?}");
173+
process::exit(CODE_READ_ERROR);
174+
},
175+
};
176+
177+
let ctx = Ctx::<JustLut<shvproto::RpcValue>>::new(&filter.lut, Vars::new([]));
178+
let outputs = filter.id.run((ctx, input_value));
179+
outputs.filter_map(|output|
180+
match output {
181+
Ok(rv) => Some(rv),
182+
Err(err) => {
183+
eprintln!("Unexpected error while processing the cq filter: {err:?}");
184+
process::exit(CODE_UNEXPECTED_ERROR)
185+
},
186+
}).collect::<Vec<_>>()
161187
} else {
162-
let mut wr = CponWriter::new(&mut writer);
163-
wr.set_no_oneliners(opts.no_oneliners);
164-
if let Some(s) = opts.indent {
165-
if s == "\\t" {
166-
wr.set_indent("\t".as_bytes());
167-
} else {
168-
wr.set_indent(s.as_bytes());
169-
}
170-
}
171-
wr.write(&rv)
172-
};
173-
if let Err(e) = res {
174-
eprintln!("Write output error: {:?}", e);
175-
process::exit(CODE_WRITE_ERROR);
188+
vec![input_value]
176189
};
190+
191+
#[cfg(not(feature = "cq"))]
192+
let output_values = vec![input_value];
193+
194+
let mut writer = BufWriter::new(stdout());
195+
for output_value in output_values {
196+
let res = if opts.chainpack_output {
197+
let mut wr = ChainPackWriter::new(&mut writer);
198+
wr.write(&output_value)
199+
} else {
200+
let mut wr = CponWriter::new(&mut writer);
201+
wr.set_no_oneliners(opts.no_oneliners);
202+
if let Some(s) = &opts.indent {
203+
if s == "\\t" {
204+
wr.set_indent("\t".as_bytes());
205+
} else {
206+
wr.set_indent(s.as_bytes());
207+
}
208+
}
209+
wr.write(&output_value)
210+
};
211+
212+
if let Err(e) = res {
213+
eprintln!("Write output error: {:?}", e);
214+
process::exit(CODE_WRITE_ERROR);
215+
};
216+
}
177217
}

0 commit comments

Comments
 (0)