1#![cfg_attr(not(test), no_std)]
2#![cfg_attr(not(test), no_main)]
3#![deny(clippy::pedantic)]
9#![deny(clippy::cargo)]
10#![deny(clippy::absolute_paths)]
11#![deny(clippy::alloc_instead_of_core)]
12#![deny(clippy::allow_attributes)]
13#![deny(clippy::allow_attributes_without_reason)]
14#![allow(
16 clippy::arithmetic_side_effects,
17 reason = "Kelvin Embedded style guide: Arithmetic side effects commonly used in embedded systems programming."
18)]
19#![allow(
20 clippy::as_conversions,
21 reason = "clippy::as_conversions explanation lost in history. TODO remove allow and find reason."
22)]
23#![deny(clippy::as_underscore)]
25#![deny(clippy::assertions_on_constants)]
26#![deny(clippy::big_endian_bytes)]
27#![deny(clippy::byte_char_slices)]
28#![deny(clippy::cfg_not_test)]
29#![deny(clippy::clone_on_ref_ptr)]
30#![deny(clippy::create_dir)]
31#![deny(clippy::dbg_macro)]
32#![deny(clippy::decimal_literal_representation)]
33#![deny(clippy::default_numeric_fallback)]
34#![deny(clippy::default_union_representation)]
35#![deny(clippy::deref_by_slicing)]
36#![deny(clippy::disallowed_script_idents)]
37#![allow(
39 clippy::duplicated_attributes,
40 reason = "https://github.com/rust-lang/rust-clippy/issues/13500"
41)]
42#![deny(clippy::else_if_without_else)]
43#![deny(clippy::empty_drop)]
44#![deny(clippy::empty_enum_variants_with_brackets)]
45#![deny(clippy::empty_structs_with_brackets)]
46#![deny(clippy::error_impl_error)]
47#![allow(
48 clippy::exhaustive_enums,
49 reason = "Kelvin Embedded style guide: allowing public enumerants is consistent with a functional style use of enumerations as pure data."
50)]
51#![allow(
52 clippy::exhaustive_structs,
53 reason = "Kelvin Embedded style guide: allowing public field access is consistent with a functional style use of data structures as pure data."
54)]
55#![deny(clippy::exit)]
56#![deny(clippy::expect_used)]
57#![deny(clippy::field_scoped_visibility_modifiers)]
58#![deny(clippy::filetype_is_file)]
59#![deny(clippy::filter_map_bool_then)]
60#![deny(clippy::float_arithmetic)]
61#![deny(clippy::float_cmp_const)]
62#![deny(clippy::fn_to_numeric_cast_any)]
63#![deny(clippy::format_push_string)]
64#![deny(clippy::get_unwrap)]
65#![deny(clippy::host_endian_bytes)]
66#![deny(clippy::if_then_some_else_none)]
67#![deny(clippy::impl_trait_in_params)]
68#![allow(
69 clippy::implicit_return,
70 reason = "Kelvin Embedded Style Guide: Implicit returns are an idiomatic approach that improves code readability."
71)]
72#![deny(clippy::indexing_slicing)]
73#![deny(clippy::infinite_loop)]
74#![deny(clippy::inline_asm_x86_att_syntax)]
75#![allow(
76 clippy::inline_asm_x86_intel_syntax,
77 reason = "clippy::inline_asm_x86_intel_syntax explanation lost in history. TODO remove allow and find reason."
78)]
79#![allow(
80 clippy::integer_division,
81 reason = "Kelvin Embedded Style Guide: Integer division is a normally used operation in embedded systems programming."
82)]
83#![allow(
84 clippy::integer_division_remainder_used,
85 reason = "Kelvin Embedded Style Guide: Integer division is a normally used operation in embedded systems programming."
86)]
87#![deny(clippy::items_after_test_module)]
88#![deny(clippy::iter_over_hash_type)]
89#![deny(clippy::large_include_file)]
90#![deny(clippy::legacy_numeric_constants)]
91#![deny(clippy::let_underscore_must_use)]
92#![deny(clippy::let_underscore_untyped)]
93#![allow(
94 clippy::little_endian_bytes,
95 reason = "Little Endian is both our target and host endianness. Preference is specifying explixit over local."
96)]
97#![deny(clippy::lossy_float_literal)]
98#![deny(clippy::manual_is_finite)]
99#![deny(clippy::manual_is_infinite)]
100#![deny(clippy::manual_next_back)]
101#![deny(clippy::manual_pattern_char_comparison)]
102#![deny(clippy::manual_rotate)]
103#![deny(clippy::manual_while_let_some)]
104#![allow(
106 clippy::min_ident_chars,
107 reason = "Single characters are useful in small namespaces and should not be mechanically prohibited."
108)]
109#![deny(clippy::map_err_ignore)]
110#![deny(clippy::mem_forget)]
111#![deny(clippy::missing_assert_message)]
112#![allow(
113 clippy::missing_asserts_for_indexing,
114 reason = "Asserts panic when false, which is prohibited in the embedded system."
115)]
116#![allow(
117 clippy::missing_docs_in_private_items,
118 reason = "clippy::missing_docs_in_private_items explanation lost in history. TODO remove allow and find reason."
119)]
120#![deny(clippy::missing_enforced_import_renames)]
121#![allow(
122 clippy::missing_inline_in_public_items,
123 reason = "clippy::missing_inline_in_public_items explanation lost in history. TODO remove allow and find reason."
124)]
125#![deny(clippy::missing_trait_methods)]
126#![deny(clippy::mixed_attributes_style)]
127#![deny(clippy::mixed_read_write_in_expression)]
128#![deny(clippy::mod_module_files)]
129#![allow(
130 clippy::modulo_arithmetic,
131 reason = "clippy::modulo_arithmetic explanation lost in history. TODO remove allow and find reason."
132)]
133#![allow(
134 clippy::multiple_crate_versions,
135 reason = "clippy::multiple_crate_versions explanation lost in history. TODO remove allow and find reason."
136)]
137#![deny(clippy::multiple_inherent_impl)]
138#![deny(clippy::multiple_unsafe_ops_per_block)]
139#![deny(clippy::mutex_atomic)]
140#![deny(clippy::needless_borrows_for_generic_args)]
141#![deny(clippy::needless_else)]
142#![deny(clippy::needless_pub_self)]
143#![deny(clippy::needless_raw_strings)]
144#![deny(clippy::needless_return_with_question_mark)]
145#![deny(clippy::non_ascii_literal)]
146#![deny(clippy::non_minimal_cfg)]
147#![deny(clippy::non_zero_suggestions)]
148#![deny(clippy::option_map_or_err_ok)]
149#![deny(clippy::panic)]
150#![deny(clippy::panic_in_result_fn)]
151#![deny(clippy::partial_pub_fields)]
152#![deny(clippy::pathbuf_init_then_push)]
153#![deny(clippy::pattern_type_mismatch)]
154#![deny(clippy::print_stderr)]
155#![deny(clippy::print_stdout)]
156#![deny(clippy::pub_use)]
157#![allow(
158 clippy::pub_with_shorthand,
159 reason = "Denying the reciprocal pub_without_shorthand."
160)]
161#![deny(clippy::pub_without_shorthand)]
162#![allow(
163 clippy::question_mark_used,
164 reason = "Allowed by Kelvin Style Guide. This is idiomatic Rust."
165)]
166#![deny(clippy::rc_buffer)]
167#![deny(clippy::rc_mutex)]
168#![deny(clippy::redundant_feature_names)]
169#![deny(clippy::redundant_type_annotations)]
170#![deny(clippy::ref_patterns)]
171#![deny(clippy::renamed_function_params)]
172#![deny(clippy::rest_pat_in_fully_bound_structs)]
173#![allow(
174 clippy::same_name_method,
175 reason = "TODO reconsider. Due to bitflags! macro"
176)]
177#![deny(clippy::self_named_module_files)]
178#![deny(clippy::semicolon_outside_block)]
179#![allow(
180 clippy::separated_literal_suffix,
181 reason = "clippy::separated_literal_suffix explanation lost in history. TODO remove allow and find reason."
182)]
183#![deny(clippy::shadow_reuse)]
184#![deny(clippy::shadow_same)]
185#![deny(clippy::shadow_unrelated)]
186#![allow(
187 clippy::single_call_fn,
188 reason = "Allowed by Kelvin style guide. This is best practice when creating well refactored code."
189)]
190#![allow(
191 clippy::single_char_lifetime_names,
192 reason = "Allowed by Kelvin style guide. Single character lifetime names are commonly used in idiomatic Rust."
193)]
194#![deny(clippy::std_instead_of_alloc)]
195#![deny(clippy::std_instead_of_core)]
196#![deny(clippy::str_to_string)]
197#![deny(clippy::string_add)]
198#![deny(clippy::string_lit_chars_any)]
199#![deny(clippy::string_slice)]
200#![deny(clippy::string_to_string)]
201#![deny(clippy::suspicious_xor_used_as_pow)]
202#![deny(clippy::tests_outside_test_module)]
203#![deny(clippy::to_string_trait_impl)]
204#![deny(clippy::todo)]
205#![deny(clippy::try_err)]
206#![deny(clippy::undocumented_unsafe_blocks)]
207#![deny(clippy::unimplemented)]
208#![deny(clippy::unnecessary_fallible_conversions)]
209#![deny(clippy::unnecessary_safety_comment)]
211#![deny(clippy::unnecessary_safety_doc)]
212#![deny(clippy::unnecessary_self_imports)]
213#![deny(clippy::unneeded_field_pattern)]
214#![deny(clippy::unreachable)]
215#![deny(clippy::unseparated_literal_suffix)]
216#![deny(clippy::unused_enumerate_index)]
217#![deny(clippy::unused_result_ok)]
218#![deny(clippy::unused_trait_names)]
219#![deny(clippy::unwrap_in_result)]
220#![deny(clippy::unwrap_used)]
221#![deny(clippy::use_debug)]
222#![deny(clippy::verbose_file_reads)]
223#![deny(clippy::wildcard_enum_match_arm)]
224
225#[macro_export]
285macro_rules! guard {
286 ($check:expr, $fail_return:expr) => {
287 if !$check {
288 return $fail_return;
289 }
290 };
291 ($check:expr) => {
292 if !$check {
293 return;
294 }
295 };
296}
297
298#[cfg(test)]
299mod tests {
300 fn use_guard_with_result(test: bool, guard_fail: TestError) -> Result<(), TestError> {
301 guard!(test, Err(guard_fail));
302 Ok(())
303 }
304 #[test]
305 fn given_a_true_condition_guard_with_result_return_type_then_ok_with_enum() {
306 assert_eq!(use_guard_with_result(true, TestError::Reason2), Ok(()));
307 }
308 #[test]
309 fn given_a_false_condition_guard_with_result_return_type_then_err_with_enum() {
310 let expected_err = TestError::Reason2;
311 assert_eq!(
312 use_guard_with_result(false, expected_err),
313 Err(expected_err)
314 );
315 }
316
317 fn use_guard_with_option(test: bool) -> Option<()> {
318 guard!(test, None);
319 Some(())
320 }
321 #[test]
322 fn given_a_true_condition_guard_with_option_return_type_then_ok_with_enum() {
323 assert_eq!(use_guard_with_option(true), Some(()));
324 }
325 #[test]
326 fn given_a_false_condition_guard_with_option_return_type_then_err_with_enum() {
327 assert_eq!(use_guard_with_option(false), None);
328 }
329
330 fn use_guard_with_string_slice(test: bool, guard_fail: &'static str) -> &'static str {
331 guard!(test, guard_fail);
332 GOOD_STRING_SLICE
333 }
334 #[test]
335 fn given_a_true_condition_guard_with_string_slice_return_type_then_ok_with_enum() {
336 assert_eq!(
337 use_guard_with_string_slice(true, BAD_STRING_SLICE),
338 GOOD_STRING_SLICE
339 );
340 }
341 #[test]
342 fn given_a_false_condition_guard_with_string_slice_return_type_then_err_with_enum() {
343 assert_eq!(
344 use_guard_with_string_slice(false, BAD_STRING_SLICE),
345 BAD_STRING_SLICE
346 );
347 }
348
349 fn use_guard_with_no_return(test: bool, run_counter: &mut usize) {
350 guard!(test);
351 *run_counter += 1;
352 }
353 #[test]
354 fn given_a_true_condition_guard_with_no_return_type_then_no_return_and_code_after_guard_ran() {
355 let mut run_counter = 0;
356 use_guard_with_no_return(true, &mut run_counter);
357 assert_eq!(1, run_counter);
358 }
359 #[test]
360 fn given_a_false_condition_guard_with_no_return_type_then_no_return_but_code_after_guard_not_run(
361 ) {
362 let mut run_counter = 0;
363 use_guard_with_no_return(false, &mut run_counter);
364 assert_eq!(0, run_counter);
365 }
366
367 #[derive(Debug, PartialEq, Clone, Copy)]
368 enum TestError {
369 _Reason1,
370 Reason2,
371 _Reason3(&'static str),
372 }
373
374 const GOOD_STRING_SLICE: &str = "Good!";
375 const BAD_STRING_SLICE: &str = "bad...";
376}