Skip to content

Commit

Permalink
Merge pull request #23 from tcharding/12-29-improve
Browse files Browse the repository at this point in the history
Do various improvements
  • Loading branch information
tcharding authored Dec 29, 2024
2 parents 0c4b4e9 + 3760ece commit 5c6ec75
Show file tree
Hide file tree
Showing 4 changed files with 220 additions and 29 deletions.
133 changes: 131 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
4 changes: 1 addition & 3 deletions examples/point.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
34 changes: 19 additions & 15 deletions rustfmt.toml
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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"
Expand All @@ -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"
Expand All @@ -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
Expand All @@ -68,6 +73,5 @@ skip_children = false
show_parse_errors = true
error_on_line_overflow = false
error_on_unformatted = false
ignore = []
emit_mode = "Files"
make_backup = false
78 changes: 69 additions & 9 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Point>,
//! }
//! ```
#![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;
Expand All @@ -30,6 +67,7 @@ pub trait ArbitraryOrd: Eq + PartialEq {
/// # Examples
///
/// ```
/// # #![allow(unused)] // Because of `Adt`.
/// use core::{cmp::Ordering, fmt};
/// use ordered::{ArbitraryOrd, Ordered};
///
Expand Down Expand Up @@ -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)]
Expand All @@ -74,6 +111,12 @@ impl<T> Ordered<T> {
/// The inner type is public so this function is never explicitly needed.
pub const fn new(inner: T) -> Self { Self(inner) }

/// Creates an `Ordered<T>` 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.
Expand All @@ -83,11 +126,6 @@ impl<T> Ordered<T> {
///
/// We also implement [`core::ops::Deref`] so this function is never explicitly needed.
pub fn into_inner(self) -> T { self.0 }

/// Creates an `Ordered<T>` 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<T: ArbitraryOrd> ArbitraryOrd for &T {
Expand Down Expand Up @@ -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<T: Send>() {}
fn assert_sync<T: Sync>() {}

assert_send::<Ordered<Point>>();
assert_sync::<Ordered<Point>>();
}
}

0 comments on commit 5c6ec75

Please sign in to comment.