1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
// enable all rustc's built-in lints
#![deny(
	future_incompatible,
	nonstandard_style,
	rust_2018_compatibility,
	rust_2018_idioms,
	rust_2021_compatibility,
	unused,
	warnings
)]
// rustc's additional allowed by default lints
#![deny(
	absolute_paths_not_starting_with_crate,
	deprecated_in_future,
	elided_lifetimes_in_paths,
	explicit_outlives_requirements,
	keyword_idents,
	macro_use_extern_crate,
	meta_variable_misuse,
	missing_abi,
	missing_copy_implementations,
	missing_debug_implementations,
	missing_docs,
	non_ascii_idents,
	noop_method_call,
	pointer_structural_match,
	rust_2021_incompatible_closure_captures,
	rust_2021_incompatible_or_patterns,
	rust_2021_prefixes_incompatible_syntax,
	rust_2021_prelude_collisions,
	single_use_lifetimes,
	trivial_casts,
	trivial_numeric_casts,
	unreachable_pub,
	unsafe_code,
	unsafe_op_in_unsafe_fn,
	unstable_features,
	unused_crate_dependencies,
	unused_extern_crates,
	unused_import_braces,
	unused_lifetimes,
	unused_macro_rules,
	unused_qualifications,
	unused_results,
	variant_size_differences
)]
// enable all of Clippy's lints
#![deny(clippy::all, clippy::cargo)]
#![deny(
	rustdoc::bare_urls,
	rustdoc::broken_intra_doc_links,
	rustdoc::invalid_codeblock_attributes,
	rustdoc::invalid_html_tags,
	rustdoc::missing_crate_level_docs,
	rustdoc::private_doc_tests,
	rustdoc::private_intra_doc_links
)]
// allow some things in tests

//! # Version Track
//!
//! This simple crate provides an easy way to track and compare changes to value that are too expensive to compare
//! directly. This crate will track mutable changes to a value, and automatically increment a version number on every
//! modification. Any comparison will then compare the internal version number, instead of having to do a full
//! comparison on a complex data structure.
//!
//! Tracking is performed by two values, the first is a V4 [uuid::Uuid], and the second is a [usize] counter. The
//! [uuid::Uuid] is generated once¹ per value being tracked, and then each subsequent mutable reference access
//! increments the counter. This allows for tracking multiple distinct values independently, using the [uuid::Uuid] to
//! track the different values across increments, and the counter to track direct changes to the value.
//!
//! The crate provides two ways to track versions. The first way is using a pointer-like wrapper around another value.
//! This is the easiest way to use this crate, but at times may result in extra unneeded version increments. To address
//! this it is possible to create a version tracker manually to be added as a field on a struct or stored separately.
//!
//! ¹ The [uuid::Uuid] value may be regenerated is the [usize] counter wraps back to zero.
//!
//! ## Basic Example
//!
//! Any value can be wrapped with [`Versioned<T>`], and because [`Versioned<T>`] implements [std::ops::Deref],
//! [std::ops::DerefMut], [std::convert::AsRef] and [std::convert::AsMut], the wrapped value can be used in most places
//! that the wrapped value is used.
//!
//! ```
//! use version_track::Versioned;
//!
//! let mut tracked_value = Versioned::new(String::from("foo"));
//! let current_version = tracked_value.version();
//! tracked_value.push_str("bar");
//!
//! assert_ne!(current_version, tracked_value.version());
//! assert_eq!(*tracked_value, "foobar");
//! ```
//!
//! ## Direct Use Example
//!
//! Sometimes more control over the version is desired, or wrapping the value to be tracked is not possible. In those
//! cases [Version] can be used directly. In this case, it is up to the developer to decide on when a change has
//! occurred. This can be useful to only track some modifications to a value, or to only increment once when multiple
//! mutable references are needed.
//!
//! ```
//! use version_track::Version;
//!
//! let mut value = String::from("foo");
//! let mut version = Version::new();
//! let current_version = version;
//!
//! value.push_str("bar");
//! version.increment();
//!
//! assert_ne!(current_version, version);
//! assert_eq!(value, "foobar");
//! ```

mod version;
mod versioned;

pub use crate::{
	version::{Version, SENTINEL_VERSION},
	versioned::Versioned,
};