Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
1eb6dce
Add clippy lints
syyyr Feb 3, 2026
da30776
Use assert! instead of if-then-panic
syyyr Feb 2, 2026
43585a6
Remove allows
syyyr Feb 3, 2026
4a63417
Fix unreadable literals
syyyr Feb 3, 2026
14237fb
Fix possible truncation
syyyr Feb 3, 2026
a91e108
Use arguments directly in format string
syyyr Feb 3, 2026
54b1b00
Fix casting issues
syyyr Feb 3, 2026
5784bcf
Fix indexing issues
syyyr Feb 3, 2026
b249058
Remove unnecessary semicolons
syyyr Feb 3, 2026
7709e7e
Use String::default
syyyr Feb 3, 2026
8912674
Add semicolon if nothing is returned
syyyr Feb 3, 2026
280182a
Use String::clone instead of String::to_string
syyyr Feb 3, 2026
4c223a2
Remove explicit into_iter for for-loops
syyyr Feb 3, 2026
9190635
Improve () matching
syyyr Feb 3, 2026
938a45a
Add must_use attrs
syyyr Feb 3, 2026
5a29403
Remove redundant match arms
syyyr Feb 3, 2026
ace687f
Do not pass Decimal/DateTime by reference
syyyr Feb 3, 2026
4ea72a8
Fix needless_pass_by_value
syyyr Feb 3, 2026
ffa540d
Remove redundant match
syyyr Feb 3, 2026
c832add
Remove unwrap
syyyr Feb 3, 2026
5b900b8
Prefer expect over allow
syyyr Feb 3, 2026
5d54f26
Remove unnecessary to_string()
syyyr Feb 3, 2026
7a100ba
Use chars instead strings where possible
syyyr Feb 3, 2026
79e116a
Elide some lifetimes
syyyr Feb 3, 2026
6ec82af
cp2cp: Allow stderr/stdout/exit
syyyr Feb 3, 2026
93c56e1
Ignore warning
syyyr Feb 3, 2026
6f5f8fc
Remove unneccessary borrow
syyyr Feb 3, 2026
48b4d45
Do not pass by value
syyyr Feb 3, 2026
3b66bf6
Improve function calls
syyyr Feb 3, 2026
f1a1a4a
Ignore warning
syyyr Feb 3, 2026
02657e1
decimal/datetime: Use self by value
syyyr Feb 3, 2026
1a5abf3
Simplify abs
syyyr Feb 3, 2026
090130c
Don't use as_bytes on literals
syyyr Feb 3, 2026
62e2b7e
Use matches!
syyyr Feb 3, 2026
ac1be9a
Use std::iter::once
syyyr Feb 3, 2026
f20376e
Remove unnecessary clone
syyyr Feb 3, 2026
481163f
Bump version
syyyr Feb 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 65 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ name = "shvproto"
description = "Rust implementation of the SHV protocol"
license = "MIT"
repository = "https://github.com/silicon-heaven/libshvproto-rs"
version = "4.0.1"
version = "5.0.0"
edition = "2024"

[dependencies]
Expand Down Expand Up @@ -38,3 +38,67 @@ specialization = []
[[bin]]
name = "cp2cp"
required-features = ["cp2cp"]

[lints.clippy]
pedantic = {priority = -1, level = "warn"}

allow_attributes = "warn"
allow_attributes_without_reason = "warn"
box_collection = "warn"
dbg_macro = "warn"
enum_variant_names = "warn"
equatable_if_let = "warn"
exit = "warn"
indexing_slicing = "warn"
infinite_loop = "warn"
iter_on_single_items = "warn"
large_types_passed_by_value = "warn"
let_underscore_must_use = "warn"
linkedlist = "warn"
map_err_ignore = "warn"
missing_assert_message = "warn"
needless_pass_by_ref_mut = "warn"
option-if-let-else = "warn"
option_option = "warn"
or_fun_call = "warn"
owned_cow = "warn"
panic = "warn"
print_stderr = "warn"
print_stdout = "warn"
rc_buffer = "warn"
rc_mutex = "warn"
redundant_allocation = "warn"
redundant_clone = "warn"
redundant_type_annotations = "warn"
ref_option = "warn"
rest_pat_in_fully_bound_structs = "warn"
return_and_then = "warn"
string_lit_as_bytes = "warn"
string_slice = "warn"
trivially_copy_pass_by_ref = "warn"
try_err = "warn"
undocumented_unsafe_blocks = "warn"
unimplemented = "warn"
unnecessary_box_returns = "warn"
unnecessary_wraps = "warn"
unneeded_field_pattern = "warn"
unused_self = "warn"
unwrap_used = "warn"
upper_case_acronyms = "warn"
useless_let_if_seq = "warn"
vec_box = "warn"
wrong_self_convention = "warn"

doc_markdown = "allow"
expect_used = "allow"
explicit_iter_loop = "allow"
float-cmp = "allow"
format_push_string = "allow"
items_after_statements = "allow"
manual_string_new = "allow"
missing_errors_doc = "allow"
missing_panics_doc = "allow"
must_use_candidate = "allow"
should_panic_without_expect = "allow"
todo = "allow"
too_many_lines = "allow"
8 changes: 8 additions & 0 deletions clippy.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
allow-expect-in-consts = true
allow-expect-in-tests = true
allow-indexing-slicing-in-tests = true
allow-one-hash-in-raw-strings = true
allow-panic-in-tests = true
allow-print-in-tests = true
allow-unwrap-in-tests = true
avoid-breaking-exported-api = false
2 changes: 1 addition & 1 deletion libshvproto-macros/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name = "libshvproto-macros"
description = "Derive macros for libshvproto"
license = "MIT"
repository = "https://github.com/silicon-heaven/libshvproto-rs"
version = "0.2.1"
version = "0.2.2"
edition = "2021"

[lib]
Expand Down
21 changes: 6 additions & 15 deletions libshvproto-macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ fn is_option(ty: &syn::Type) -> bool {
if !(typepath.qself.is_none() && typepath.path.segments.len() == 1) {
return false
}
let segment = &typepath.path.segments[0];
let segment = typepath.path.segments.first().expect("len() is 1");

if segment.ident != "Option" {
return false;
Expand All @@ -27,7 +27,7 @@ fn is_option(ty: &syn::Type) -> bool {
return false;
}

matches!(data.args[0], syn::GenericArgument::Type(_))
matches!(data.args.first().expect("len() is 1"), syn::GenericArgument::Type(_))
}

fn get_type(ty: &syn::Type) -> Option<String> {
Expand All @@ -48,8 +48,7 @@ fn get_field_name(field: &syn::Field) -> String {
.and_then(|attr| attr.meta.require_name_value().ok())
.filter(|meta_name_value| meta_name_value.path.is_ident("field_name"))
.map(|meta_name_value| if let syn::Expr::Lit(expr) = &meta_name_value.value { expr } else { panic!("Expected a string literal for 'field_name'") })
.map(|literal| if let syn::Lit::Str(expr) = &literal.lit { expr.value() } else { panic!("Expected a string literal for 'field_name'") })
.unwrap_or_else(|| field.ident.as_ref().unwrap().to_string().to_case(Case::Camel))
.map_or_else(|| field.ident.as_ref().unwrap().to_string().to_case(Case::Camel), |literal| if let syn::Lit::Str(expr) = &literal.lit { expr.value() } else { panic!("Expected a string literal for 'field_name'") })
}

fn field_to_initializers(
Expand All @@ -63,11 +62,7 @@ fn field_to_initializers(
let is_option = is_option(&field.ty);
let struct_initializer;
let rpcvalue_insert;
let identifier_at_value = if let Some(value) = from_value {
quote! { #value.#identifier }
} else {
quote! { #identifier }
};
let identifier_at_value = from_value.map_or_else(|| quote! { #identifier }, |value| quote! { #value.#identifier });
if is_option {
struct_initializer = quote!{
#identifier: match get_key(#field_name).ok() {
Expand Down Expand Up @@ -235,9 +230,7 @@ pub fn derive_from_rpcvalue(item: TokenStream) -> TokenStream {
};
match &variant.fields {
syn::Fields::Unnamed(variant_types) => {
if variant_types.unnamed.len() != 1 {
panic!("Only single element variant tuples are supported for FromRpcValue");
}
assert!(variant_types.unnamed.len() == 1, "Only single element variant tuples are supported for FromRpcValue");
let source_variant_type = &variant_types.unnamed.first().expect("No tuple elements").ty;
let deref_code = quote!((*x));
let unbox_code = quote!((x.as_ref().clone()));
Expand Down Expand Up @@ -431,9 +424,7 @@ pub fn derive_to_rpcvalue(item: TokenStream) -> TokenStream {
let variant_ident = &variant.ident;
match &variant.fields {
syn::Fields::Unnamed(variant_types) => {
if variant_types.unnamed.len() != 1 {
panic!("Only single element variant tuples are supported for ToRpcValue");
}
assert!(variant_types.unnamed.len() == 1, "Only single element variant tuples are supported for ToRpcValue");
match_arms_ser.extend(quote!{
#struct_identifier::#variant_ident(val) => shvproto::RpcValue::from(val),
});
Expand Down
39 changes: 19 additions & 20 deletions src/bin/cp2cp.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#![allow(clippy::print_stderr, clippy::print_stdout, clippy::exit, reason = "Fine for a binary")]
use clap::Parser;
use log::LevelFilter;
use shvproto::reader::ReadErrorReason;
Expand All @@ -15,6 +16,7 @@ use jaq_all::{jaq_core::{Ctx, Vars, data::JustLut}, jaq_std};

#[derive(Parser, Debug)]
#[structopt(name = "cp2cp", version = env!("CARGO_PKG_VERSION"), author = env!("CARGO_PKG_AUTHORS"), about = "ChainPack to Cpon and back utility")]
#[expect(clippy::struct_excessive_bools, reason = "Fine for cli args")]
struct Cli {
#[arg(short, long, help = "Cpon indentation string")]
indent: Option<String>,
Expand Down Expand Up @@ -53,24 +55,20 @@ struct ChainPackRpcBlockResult {
}
fn print_option<T: Display>(n: Option<T>) {
if let Some(n) = n {
println!("{}", n);
println!("{n}");
} else {
println!();
}
}
fn exit_with_result_and_code(result: &ChainPackRpcBlockResult, error: Option<ReadErrorReason>) -> ! {
let exit_code = if let Some(error) = &error {
match error {
ReadErrorReason::UnexpectedEndOfStream => CODE_NOT_ENOUGH_DATA,
ReadErrorReason::NotEnoughPrecision => CODE_READ_ERROR,
ReadErrorReason::InvalidCharacter => {
eprintln!("Parse input error: {:?}", error);
CODE_READ_ERROR
}
let exit_code = error.map_or(CODE_SUCCESS, |error| match error {
ReadErrorReason::UnexpectedEndOfStream => CODE_NOT_ENOUGH_DATA,
ReadErrorReason::NotEnoughPrecision => CODE_READ_ERROR,
ReadErrorReason::InvalidCharacter => {
eprintln!("Parse input error: {error:?}");
CODE_READ_ERROR
}
} else {
CODE_SUCCESS
};
});
print_option(result.block_length);
print_option(result.frame_length);
print_option(result.proto);
Expand All @@ -85,6 +83,7 @@ fn process_chainpack_rpc_block(mut reader: Box<dyn BufRead>) -> ! {
cpon: "".to_string(),
};
let mut rd = ChainPackReader::new(&mut reader);
#[expect(clippy::cast_possible_truncation, reason = "We assume pointer size is 64-bit")]
match rd.read_uint_data() {
Ok(frame_length) => {
result.block_length = Some(frame_length as usize + rd.position());
Expand All @@ -106,10 +105,10 @@ fn process_chainpack_rpc_block(mut reader: Box<dyn BufRead>) -> ! {
Err(e) => {
exit_with_result_and_code(&result, Some(e.reason));
}
};
}
match rd.read() {
Ok(rv) => {
result.cpon = rv.to_cpon().to_string();
result.cpon = rv.to_cpon();
exit_with_result_and_code(&result, None);
}
Err(e) => {
Expand All @@ -133,7 +132,7 @@ fn main() {
logger = logger.with_module_level(&module_name, LevelFilter::Trace);
}
}
logger.init().unwrap();
logger.init().expect("Logger must work");

if opts.chainpack_rpc_block {
opts.indent = None;
Expand All @@ -143,7 +142,7 @@ fn main() {

let mut reader: Box<dyn BufRead> = match opts.file {
None => Box::new(BufReader::new(io::stdin())),
Some(filename) => Box::new(BufReader::new(fs::File::open(filename).unwrap())),
Some(filename) => Box::new(BufReader::new(fs::File::open(filename).expect("Opening files must work"))),
};

let read_result = if opts.cpon_input {
Expand All @@ -158,7 +157,7 @@ fn main() {

let input_value = match read_result {
Err(e) => {
eprintln!("Parse input error: {:?}", e);
eprintln!("Parse input error: {e:?}");
process::exit(CODE_READ_ERROR);
}
Ok(rv) => rv,
Expand Down Expand Up @@ -201,7 +200,7 @@ fn main() {
wr.set_no_oneliners(opts.no_oneliners);
if let Some(s) = &opts.indent {
if s == "\\t" {
wr.set_indent("\t".as_bytes());
wr.set_indent(b"\t");
} else {
wr.set_indent(s.as_bytes());
}
Expand All @@ -210,8 +209,8 @@ fn main() {
};

if let Err(e) = res {
eprintln!("Write output error: {:?}", e);
eprintln!("Write output error: {e:?}");
process::exit(CODE_WRITE_ERROR);
};
}
}
}
Loading