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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
//! Fast lexical integer-to-string conversion routines.
//!
//! The default implementations use power reduction to unroll
//! 4 loops at a time to minimize the number of required divisions,
//! leading to massive performance gains. In addition, decimal
//! strings pre-calculate the number of digits, avoiding temporary buffers.
//!
//! A compact, fallback algorithm uses a naive, simple algorithm,
//! where each loop generates a single digit. This comes at a performance
//! penalty, but produces smaller binaries.
//!
//! # Features
//!
//! * `std` - Use the standard library.
//! * `power-of-two` - Add support for writing power-of-two integer strings.
//! * `radix` - Add support for strings of any radix.
//! * `compact` - Reduce code size at the cost of performance.
//! * `safe` - Ensure only memory-safe indexing is used.
//!
//! # Note
//!
//! Only documented functionality is considered part of the public API:
//! any of the modules, internal functions, or structs may change
//! release-to-release without major or minor version changes. Use
//! internal implementation details at your own risk.
//!
//! lexical-write-integer mainly exists as an implementation detail for
//! lexical-core, although its API is stable. If you would like to use
//! a high-level API that writes to and parses from `String` and `&str`,
//! respectively, please look at [lexical](https://crates.io/crates/lexical)
//! instead. If you would like an API that supports multiple numeric
//! conversions, please look at [lexical-core](https://crates.io/crates/lexical-core)
//! instead.
//!
//! # Version Support
//!
//! The minimum, standard, required version is 1.63.0, for const generic
//! support. Older versions of lexical support older Rust versions.
//!
//! # Design
//!
//! - [Algorithm Approach](https://github.com/Alexhuszagh/rust-lexical/blob/main/lexical-write-integer/docs/Algorithm.md)
//! - [Benchmarks](https://github.com/Alexhuszagh/rust-lexical/blob/main/lexical-write-integer/docs/Benchmarks.md)
//! - [Comprehensive Benchmarks](https://github.com/Alexhuszagh/lexical-benchmarks)
//!
//! # Safety
//!
//! This module uses a some more unsafe code for moderately acceptable
//! performance. The compact decimal serializer has no non-local safety
//! invariants, which since it's focused on code size rather than performance,
//! this trade-off is acceptable and it uses a temporary, over-allocated buffer
//! as an intermediate.
//!
//! The decimal writer relies on pre-computed tables and an exact calculation
//! of the digit count ([`digit_count`]) to avoid any overhead. Avoid
//! intermediary copies is **CRITICAL** for fast performance so the entire
//! buffer must be known but assigned to use algorithms the compiler cannot
//! easily verify. This is because we use multi-digit optimizations with our
//! pre-computed tables, so we cannot just iterate over the slice and assign
//! iteratively. Using checked indexing can lead to 30%+ decreases in
//! performance. However, with careful analysis and factoring of the code, it's
//! fairly easy to demonstrate the safety as long as the caller ensures at least
//! the required number of digits are provided.
//!
//! Our algorithms work like this, carving off the lower digits and writing them
//! to the back of the buffer.
//!
//! ```rust,ignore
//! let mut value = 12345u32;
//! let buffer = [0u8; 32];
//! let digits = value.digit_count();
//! let bytes = buffer[..digits];
//!
//! let radix = 10;
//! let radix2 = radix * radix;
//! let radix4 = radix2 * radix2
//! let mut index = bytes.len();
//! while value >= 10000 {
//!     let r = value % radix4;
//!     value /= radix4;
//!     let r1 = 2 * (r / radix2) as usize;
//!     let r2 = 2 * (r % radix2) as usize;
//!
//!     // write 5, then 4
//!     index -= 1;
//!     bytes[index] = table[r2 + 1];
//!     index -= 1;
//!     bytes[index] = table[r2];
//!
//!     // write 3 then 2
//!     index -= 1;
//!     bytes[index] = table[r1 + 1];
//!     index -= 1;
//!     bytes[index] = table[r1];
//! }
//!
//! // oontinue with radix^2 and then a single digit.
//! ```
//!
//! We can efficiently determine at compile time if the pre-computed
//! tables are large enough so there are no non-local safety considerations
//! there. The current logic call stack is:
//! 1. [`to_lexical`]
//! 2. [decimal][dec], compact, or radix (gets the correct tables and calls
//!    algorithm)
//! 3. [algorithm]
//!
//! [decimal][dec], compact, and radix therefore **MUST** be safe and do type
//! check of the bounds to avoid too much exposure to unsafety. Only
//! [`algorithm`] should have any unsafety associated with it. That is, as long
//! as the direct caller has ensure the proper buffer is allocated, there are
//! non-local safety invariants.
//!
//! [`digit_count`]: crate::decimal::DigitCount
//! [`to_lexical`]: crate::ToLexical::to_lexical
//! [dec]: crate::decimal::Decimal::decimal
//! [`algorithm`]: crate::algorithm::algorithm

// We want to have the same safety guarantees as Rust core,
// so we allow unused unsafe to clearly document safety guarantees.
#![allow(unused_unsafe)]
#![cfg_attr(feature = "lint", warn(unsafe_op_in_unsafe_fn))]
#![cfg_attr(not(feature = "std"), no_std)]
#![deny(
    clippy::doc_markdown,
    clippy::unnecessary_safety_comment,
    clippy::semicolon_if_nothing_returned,
    clippy::unwrap_used,
    clippy::as_underscore,
    clippy::doc_markdown
)]
#![allow(
    // used when concepts are logically separate
    clippy::match_same_arms,
    // loss of precision is intentional
    clippy::integer_division,
    // mathematical names use 1-character identifiers
    clippy::min_ident_chars,
    // these are not cryptographically secure contexts
    clippy::integer_division_remainder_used,
    // this can be intentional
    clippy::module_name_repetitions,
    // this is intentional: already passing a pointer and need performance
    clippy::needless_pass_by_value,
    // we use this for inline formatting for unsafe blocks
    clippy::semicolon_inside_block,
)]

pub mod algorithm;
pub mod compact;
pub mod decimal;
pub mod digit_count;
pub mod jeaiii;
pub mod options;
pub mod radix;
pub mod table;
pub mod write;

mod api;
mod table_binary;
mod table_decimal;
mod table_radix;

// Re-exports
pub use lexical_util::constants::{FormattedSize, BUFFER_SIZE};
pub use lexical_util::format::{self, NumberFormatBuilder};
pub use lexical_util::options::WriteOptions;

pub use self::api::{ToLexical, ToLexicalWithOptions};
#[doc(inline)]
pub use self::options::{Options, OptionsBuilder};