diff --git a/Cargo.toml b/Cargo.toml index 9ff7b95..2b14e17 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,11 +11,140 @@ keywords = ["ord", "partialord", "wrapper"] readme = "README.md" edition = "2021" rust-version = "1.63.0" -exclude = ["justfile", "rustfmt.toml", "clippy.toml"] +exclude = ["tests", "contrib"] + +[features] [dependencies] -[features] +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] [[example]] name = "point" + +[lints.clippy] +# Exhaustive list of pedantic clippy lints +assigning_clones = "warn" +bool_to_int_with_if = "warn" +borrow_as_ptr = "warn" +case_sensitive_file_extension_comparisons = "warn" +cast_lossless = "warn" +cast_possible_truncation = "warn" +cast_possible_wrap = "warn" +cast_precision_loss = "warn" +cast_ptr_alignment = "warn" +cast_sign_loss = "warn" +checked_conversions = "warn" +cloned_instead_of_copied = "warn" +copy_iterator = "warn" +default_trait_access = "warn" +doc_link_with_quotes = "warn" +doc_markdown = "warn" +empty_enum = "warn" +enum_glob_use = "warn" +expl_impl_clone_on_copy = "warn" +explicit_deref_methods = "warn" +explicit_into_iter_loop = "warn" +explicit_iter_loop = "warn" +filter_map_next = "warn" +flat_map_option = "warn" +float_cmp = "warn" +fn_params_excessive_bools = "warn" +from_iter_instead_of_collect = "warn" +if_not_else = "warn" +ignored_unit_patterns = "warn" +implicit_clone = "warn" +implicit_hasher = "warn" +inconsistent_struct_constructor = "warn" +index_refutable_slice = "warn" +inefficient_to_string = "warn" +inline_always = "warn" +into_iter_without_iter = "warn" +invalid_upcast_comparisons = "warn" +items_after_statements = "warn" +iter_filter_is_ok = "warn" +iter_filter_is_some = "warn" +iter_not_returning_iterator = "warn" +iter_without_into_iter = "warn" +large_digit_groups = "warn" +large_futures = "warn" +large_stack_arrays = "warn" +large_types_passed_by_value = "warn" +linkedlist = "warn" +macro_use_imports = "warn" +manual_assert = "warn" +manual_instant_elapsed = "warn" +manual_is_power_of_two = "warn" +manual_is_variant_and = "warn" +manual_let_else = "warn" +manual_ok_or = "warn" +manual_string_new = "warn" +many_single_char_names = "warn" +map_unwrap_or = "warn" +match_bool = "warn" +match_on_vec_items = "warn" +match_same_arms = "warn" +match_wild_err_arm = "warn" +match_wildcard_for_single_variants = "warn" +maybe_infinite_iter = "warn" +mismatching_type_param_order = "warn" +missing_errors_doc = "warn" +missing_fields_in_debug = "warn" +missing_panics_doc = "warn" +must_use_candidate = "warn" +mut_mut = "warn" +naive_bytecount = "warn" +needless_bitwise_bool = "warn" +needless_continue = "warn" +needless_for_each = "warn" +needless_pass_by_value = "warn" +needless_raw_string_hashes = "warn" +no_effect_underscore_binding = "warn" +no_mangle_with_rust_abi = "warn" +option_as_ref_cloned = "warn" +option_option = "warn" +ptr_as_ptr = "warn" +ptr_cast_constness = "warn" +pub_underscore_fields = "warn" +range_minus_one = "warn" +range_plus_one = "warn" +redundant_closure_for_method_calls = "warn" +redundant_else = "warn" +ref_as_ptr = "warn" +ref_binding_to_reference = "warn" +ref_option = "warn" +ref_option_ref = "warn" +return_self_not_must_use = "warn" +same_functions_in_if_condition = "warn" +semicolon_if_nothing_returned = "warn" +should_panic_without_expect = "warn" +similar_names = "warn" +single_char_pattern = "warn" +single_match_else = "warn" +stable_sort_primitive = "warn" +str_split_at_newline = "warn" +string_add_assign = "warn" +struct_excessive_bools = "warn" +struct_field_names = "warn" +too_many_lines = "warn" +transmute_ptr_to_ptr = "warn" +trivially_copy_pass_by_ref = "warn" +unchecked_duration_subtraction = "warn" +unicode_not_nfc = "warn" +uninlined_format_args = "allow" # This is a subjective style choice. +unnecessary_box_returns = "warn" +unnecessary_join = "warn" +unnecessary_literal_bound = "warn" +unnecessary_wraps = "warn" +unnested_or_patterns = "warn" +unreadable_literal = "warn" +unsafe_derive_deserialize = "warn" +unused_async = "warn" +unused_self = "warn" +used_underscore_binding = "warn" +used_underscore_items = "warn" +verbose_bit_mask = "warn" +wildcard_imports = "warn" +zero_sized_map_values = "warn" diff --git a/examples/point.rs b/examples/point.rs index b4bdb95..f8875df 100644 --- a/examples/point.rs +++ b/examples/point.rs @@ -17,9 +17,7 @@ fn main() { println!(); println!("Looking in map for key: {}", a); - let found = map - .get(Ordered::from_ref(&a)) - .expect("failed to look up key"); + let found = map.get(Ordered::from_ref(&a)).expect("failed to look up key"); println!("Found it, with value: {}", found); } diff --git a/rustfmt.toml b/rustfmt.toml index 88289b2..08c331b 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,19 +1,24 @@ -max_width = 100 +ignore = [] hard_tabs = false tab_spaces = 4 newline_style = "Auto" indent_style = "Block" -use_small_heuristics = "Default" -fn_call_width = 80 -attr_fn_like_width = 70 -struct_lit_width = 80 -struct_variant_width = 35 -array_width = 60 -chain_width = 60 -single_line_if_else_max_width = 50 + +max_width = 100 # This is number of characters. +# `use_small_heuristics` is ignored if the granular width config values are explicitly set. +use_small_heuristics = "Max" # "Max" == All granular width settings same as `max_width`. +# # Granular width configuration settings. These are percentages of `max_width`. +# fn_call_width = 60 +# attr_fn_like_width = 70 +# struct_lit_width = 18 +# struct_variant_width = 35 +# array_width = 60 +# chain_width = 60 +# single_line_if_else_max_width = 50 + wrap_comments = false format_code_in_doc_comments = false -comment_width = 80 +comment_width = 100 # Default 80 normalize_comments = false normalize_doc_attributes = false format_strings = false @@ -22,7 +27,7 @@ format_macro_bodies = true hex_literal_case = "Preserve" empty_item_single_line = true struct_lit_single_line = true -fn_single_line = true +fn_single_line = true # Default false where_single_line = false imports_indent = "Block" imports_layout = "Mixed" @@ -41,7 +46,7 @@ combine_control_expr = true overflow_delimited_expr = false struct_field_align_threshold = 0 enum_discrim_align_threshold = 0 -match_arm_blocks = true +match_arm_blocks = false # Default true match_arm_leading_pipes = "Never" force_multiline_blocks = false fn_params_layout = "Tall" @@ -52,8 +57,8 @@ trailing_comma = "Vertical" match_block_trailing_comma = false blank_lines_upper_bound = 1 blank_lines_lower_bound = 0 -edition = "2018" -version = "One" +edition = "2021" +style_edition = "2021" inline_attribute_width = 0 format_generated_files = true merge_derives = true @@ -65,9 +70,8 @@ color = "Auto" unstable_features = false disable_all_formatting = false skip_children = false -hide_parse_errors = false +show_parse_errors = true error_on_line_overflow = false error_on_unformatted = false -ignore = [] emit_mode = "Files" make_backup = false diff --git a/src/lib.rs b/src/lib.rs index 2717e63..f40a1d7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,13 +3,50 @@ //! Provides a wrapper for types that can technically implement `PartialOrd`/`Ord` //! but for semantic reasons it is nonsensical. //! -//! For examples see the docs on [`Ordered`] or the code in `examples/point.rs`. +//! # Examples +//! +//! ``` +//! # #![allow(unused)] // Because of `Adt`. +//! use core::{cmp::Ordering, fmt}; +//! use ordered::{ArbitraryOrd, Ordered}; +//! +//! /// A point in 2D space. +//! /// +//! /// We do not want users to be able to write `a < b` because it is not well defined. +//! #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +//! struct Point { +//! x: u32, +//! y: u32, +//! } +//! +//! impl ArbitraryOrd for Point { +//! fn arbitrary_cmp(&self, other: &Self) -> Ordering { +//! // Just use whatever order tuple cmp gives us. +//! (self.x, self.y).cmp(&(other.x, other.y)) +//! } +//! } +//! +//! impl fmt::Display for Point { +//! fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +//! write!(f, "({}, {})", self.x, self.y) +//! } +//! } +//! +//! /// `Ordered` allows users to derive `PartialOrd` on types that include a `Point`. +//! #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +//! struct Adt { +//! name: String, +//! point: Ordered, +//! } +//! ``` #![no_std] // Experimental features we need. #![cfg_attr(docsrs, feature(doc_auto_cfg))] // Coding conventions. #![warn(missing_docs)] +#![warn(deprecated_in_future)] +#![doc(test(attr(warn(unused))))] use core::borrow::{Borrow, BorrowMut}; use core::cmp::Ordering; @@ -30,6 +67,7 @@ pub trait ArbitraryOrd: Eq + PartialEq { /// # Examples /// /// ``` +/// # #![allow(unused)] // Because of `Adt`. /// use core::{cmp::Ordering, fmt}; /// use ordered::{ArbitraryOrd, Ordered}; /// @@ -58,9 +96,8 @@ pub trait ArbitraryOrd: Eq + PartialEq { /// let point = Point { x: 0, y: 1 }; /// let ordered = Ordered(point); /// -/// println!("We can explicitly deref (*ordered): {}", *ordered); -/// println!("Or use deref coercion (ordered): {}", ordered); -/// println!("Or we can use borrow (&ordered): {}", &ordered); +/// assert_eq!(*ordered, ordered.into_inner()); // Explicitly deref or use `into_inner()`. +/// assert_eq!(&ordered.0, ordered.as_ref()); // Use `AsRef` or `as_ref()`. /// ``` #[derive(Debug, Clone, PartialEq, Eq, Hash)] #[repr(transparent)] @@ -74,6 +111,12 @@ impl Ordered { /// The inner type is public so this function is never explicitly needed. pub const fn new(inner: T) -> Self { Self(inner) } + /// Creates an `Ordered` from a reference. + /// + /// This allows: `let found = map.get(Ordered::from_ref(&a));` + #[allow(clippy::ptr_as_ptr)] + pub fn from_ref(value: &T) -> &Self { unsafe { &*(value as *const _ as *const Self) } } + /// Returns a reference to the inner object. /// /// We also implement [`core::borrow::Borrow`] so this function is never explicitly needed. @@ -83,11 +126,6 @@ impl Ordered { /// /// We also implement [`core::ops::Deref`] so this function is never explicitly needed. pub fn into_inner(self) -> T { self.0 } - - /// Creates an `Ordered` from a reference. - /// - /// This allows: `let found = map.get(Ordered::from_ref(&a));` - pub fn from_ref(value: &T) -> &Self { unsafe { &*(value as *const _ as *const Self) } } } impl ArbitraryOrd for &T { @@ -179,4 +217,26 @@ mod tests { assert!(Ordered(&a) < Ordered(&b)); } + + // Copied from https://rust-lang.github.io/api-guidelines/interoperability.html#c-send-sync + #[test] + fn send() { + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] + struct Point { + x: u32, + y: u32, + } + + impl ArbitraryOrd for Point { + fn arbitrary_cmp(&self, other: &Self) -> Ordering { + (self.x, self.y).cmp(&(other.x, other.y)) + } + } + + fn assert_send() {} + fn assert_sync() {} + + assert_send::>(); + assert_sync::>(); + } }