1#![doc(
2 html_logo_url = "https://avatars.githubusercontent.com/u/91469139?s=128",
3 html_favicon_url = "https://avatars.githubusercontent.com/u/91469139?s=256"
4)]
5#![cfg_attr(any(doc, test), doc = include_str!("../README.md"))]
6#![cfg_attr(not(any(doc, test)), doc = env!("CARGO_PKG_NAME"))]
7#![deny(nonstandard_style, rustdoc::all, trivial_casts, trivial_numeric_casts)]
8#![forbid(non_ascii_idents, unsafe_code)]
9#![deny(
10 clippy::cfg_not_test,
11 clippy::dbg_macro,
12 clippy::empty_drop,
13 clippy::equatable_if_let,
14 clippy::empty_structs_with_brackets,
15 clippy::empty_enum_variants_with_brackets,
16 clippy::exit,
17 clippy::todo,
18 clippy::unwrap_used
19)]
20#![warn(
21 clippy::absolute_paths,
22 clippy::as_conversions,
23 clippy::allow_attributes_without_reason,
24 clippy::as_pointer_underscore,
25 clippy::as_ptr_cast_mut,
26 clippy::assertions_on_result_states,
27 clippy::branches_sharing_code,
28 clippy::clear_with_drain,
29 clippy::clone_on_ref_ptr,
30 clippy::collection_is_never_read,
31 clippy::create_dir,
32 clippy::debug_assert_with_mut_call,
33 clippy::default_union_representation,
34 clippy::derive_partial_eq_without_eq,
35 clippy::doc_include_without_cfg,
36 clippy::fallible_impl_from,
37 clippy::filetype_is_file,
38 clippy::float_cmp_const,
39 clippy::fn_to_numeric_cast_any,
40 clippy::get_unwrap,
41 clippy::if_then_some_else_none,
42 clippy::implicit_clone,
43 clippy::imprecise_flops,
44 clippy::infinite_loop,
45 clippy::iter_on_empty_collections,
46 clippy::iter_on_single_items,
47 clippy::iter_over_hash_type,
48 clippy::iter_with_drain,
49 clippy::large_include_file,
50 clippy::large_stack_frames,
51 clippy::let_underscore_untyped,
52 clippy::literal_string_with_formatting_args,
53 clippy::lossy_float_literal,
54 clippy::map_err_ignore,
55 clippy::map_with_unused_argument_over_ranges,
56 clippy::mem_forget,
57 clippy::missing_assert_message,
58 clippy::missing_const_for_fn,
59 clippy::module_name_repetitions,
60 clippy::multiple_inherent_impl,
61 clippy::multiple_unsafe_ops_per_block,
62 clippy::mutex_atomic,
63 clippy::mutex_integer,
64 clippy::needless_collect,
65 clippy::needless_pass_by_ref_mut,
66 clippy::needless_raw_strings,
67 clippy::non_zero_suggestions,
68 clippy::nonstandard_macro_braces,
69 clippy::option_if_let_else,
70 clippy::or_fun_call,
71 clippy::panic_in_result_fn,
72 clippy::partial_pub_fields,
73 clippy::pathbuf_init_then_push,
74 clippy::pedantic,
75 clippy::precedence_bits,
76 clippy::pub_without_shorthand,
77 clippy::rc_buffer,
78 clippy::rc_mutex,
79 clippy::read_zero_byte_vec,
80 clippy::redundant_clone,
81 clippy::redundant_type_annotations,
82 clippy::renamed_function_params,
83 clippy::ref_patterns,
84 clippy::rest_pat_in_fully_bound_structs,
85 clippy::return_and_then,
86 clippy::same_name_method,
87 clippy::semicolon_inside_block,
88 clippy::set_contains_or_insert,
89 clippy::shadow_unrelated,
90 clippy::significant_drop_in_scrutinee,
91 clippy::significant_drop_tightening,
92 clippy::str_to_string,
93 clippy::string_add,
94 clippy::string_lit_as_bytes,
95 clippy::string_lit_chars_any,
96 clippy::string_slice,
97 clippy::suboptimal_flops,
98 clippy::suspicious_operation_groupings,
99 clippy::suspicious_xor_used_as_pow,
100 clippy::tests_outside_test_module,
101 clippy::too_long_first_doc_paragraph,
102 clippy::trailing_empty_array,
103 clippy::transmute_undefined_repr,
104 clippy::trivial_regex,
105 clippy::try_err,
106 clippy::undocumented_unsafe_blocks,
107 clippy::unimplemented,
108 clippy::uninhabited_references,
109 clippy::unnecessary_safety_comment,
110 clippy::unnecessary_safety_doc,
111 clippy::unnecessary_self_imports,
112 clippy::unnecessary_struct_initialization,
113 clippy::unused_peekable,
114 clippy::unused_result_ok,
115 clippy::unused_trait_names,
116 clippy::unwrap_in_result,
117 clippy::use_debug,
118 clippy::use_self,
119 clippy::useless_let_if_seq,
120 clippy::verbose_file_reads,
121 clippy::while_float,
122 ambiguous_negative_literals,
123 closure_returning_async_block,
124 future_incompatible,
125 impl_trait_redundant_captures,
126 let_underscore_drop,
127 macro_use_extern_crate,
128 meta_variable_misuse,
129 missing_copy_implementations,
130 missing_debug_implementations,
131 missing_docs,
132 redundant_lifetimes,
133 rust_2018_idioms,
134 single_use_lifetimes,
135 unit_bindings,
136 unnameable_types,
137 unreachable_pub,
138 unstable_features,
139 unused,
140 variant_size_differences
141)]
142
143mod client;
144#[cfg(feature = "discovery")]
145pub mod discovery;
147pub mod error;
149mod proto;
150
151pub use client::{EspHomeClient, EspHomeClientBuilder, EspHomeClientWriteStream};
152pub mod types {
154 pub use super::proto::*;
155}
156pub use proto::API_VERSION;
157
158pub fn convert_gatt_uuid(uuid: &[u64]) -> Result<Vec<u8>, &'static str> {
164 if uuid.len() != 2 {
165 return Err("UUID must be exactly 2 u64 values");
166 }
167 let high = uuid[0];
168 let low = uuid[1];
169 Ok([high.to_be_bytes(), low.to_be_bytes()].concat())
170}
171
172#[cfg(test)]
173mod tests {
174 use super::*;
175
176 #[test]
177 fn test_convert_gatt_uuid_valid() {
178 let uuid = [0x1122_3344_5566_7788, 0x99aa_bbcc_ddee_ff00];
179 let result = convert_gatt_uuid(&uuid).unwrap();
180 let expected = [
181 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
182 0xff, 0x00,
183 ];
184 assert_eq!(result, expected);
185 }
186
187 #[test]
188 fn test_convert_gatt_uuid_invalid_length_empty() {
189 let uuid: [u64; 0] = [];
190 assert_eq!(
191 convert_gatt_uuid(&uuid),
192 Err("UUID must be exactly 2 u64 values")
193 );
194 }
195
196 #[test]
197 fn test_convert_gatt_uuid_invalid_length_one() {
198 let uuid = [0x1234_5678_9abc_def0];
199 assert_eq!(
200 convert_gatt_uuid(&uuid),
201 Err("UUID must be exactly 2 u64 values")
202 );
203 }
204
205 #[test]
206 fn test_convert_gatt_uuid_invalid_length_three() {
207 let uuid = [1, 2, 3];
208 assert_eq!(
209 convert_gatt_uuid(&uuid),
210 Err("UUID must be exactly 2 u64 values")
211 );
212 }
213}