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
172
173
174
175
176
177
178
179
180
181
//! # The `ucsi` library
//!
//! The ucsi (cast SI) library provides SI-based unit typing system
//! and zero-cost unit wrapper for values.
//!
//! You can use the values of these packages for normal arithmetic
//! (since they overload the operators),
//! and then rust's generic engine and ucsi will help you derive their types.
//!
//! Thanks to rust's powerful type system and static evaluator,
//! ucsi lets you know at compile time what your arithmetic violates,
//! and there's perfect support for constant arithmetic.
//!
//! At the same time, you can easily create your own types
//! (see [`unit!`] macro and the [`macros`] module)
//! that work seamlessly with ucsi's type system.
//!
//! ## Quick start
//!
//! ```rust
//! use ucsi::units::base::{kg, m, s};
//! use ucsi::unit;
//! use ucsi::Value;
//!
//! // create your new unit
//! // see the `unit` macro or `ucsi::core::ops` for more information.
//! type Newton = unit!((kg * m) / (s ** { 2 }));
//!
//! // build some value
//! // `Value<value_type, value_unit>`
//! let speed: Value<f64, unit!(m / s)> = Value::new(10.0);
//! let time: Value<f64, s> = Value::new(1.0);
//! let acc = speed / time;
//! let mass: Value<f64, kg> = Value::new(1.0);
//! // this is `newton` in SI,
//! // but not now because it's currently typed as `((m / s) / s) * kg`
//! let force = acc * mass;
//! // lets cast it to newton
//! let checked_force: Value<_, Newton> =
//! // note the `cast_const` here. `f64` is copy, so this cast is const-able.
//! // If your value is not copy-able, use `cast` instead.
//! force.cast_const();
//! ```
//!
//! Thanks to rust's const evaluation, the type-casting is **compile-time checked**!
//!
//! To clearify the type-casting check, consider the following example:
//!
//! ```rust,compile_fail
//! # use ucsi::units::base::{kg, m, s};
//! # use ucsi::unit;
//! # use ucsi::Value;
//! # type Newton = unit!((kg * m) / (s ** { 2 }));
//! # let speed: Value<f64, unit!(m / s)> = Value::new(10.0);
//! # let time: Value<f64, s> = Value::new(1.0);
//! # let acc = speed / time;
//! # let mass: Value<f64, kg> = Value::new(1.0);
//! # let force = acc * mass;
//! let s_can_never_be_newton: Value<_, s> = force.cast_const();
//! ```
//!
//! The example above cannot compile, and will throw some error like this:
//!
//! ```plain
//! error[E0080]: evaluation of `<Second as CastFrom<ucsi::ops::Mul<ucsi::ops::Div<ucsi::ops::Div<Meter, Second>, Second>,
//! Kilogram>>>::CAN_CAST_FROM` failed
//! --> D:\WBH\rust\ucsi\ucsi\src\core\units\any.rs:25:9
//! |
//! 25 | panic!("cannot cast si type")
//! | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'cannot cast si type', D:\WBH\rust\ucsi\ucsi\src\core\units\any.rs:25:9
//! |
//! note: inside `is_same_type_or_panic::<ucsi::ops::Mul<ucsi::ops::Div<ucsi::ops::Div<Meter, Second>, Second>, Kilogram>,
//! Second>`
//! --> D:\WBH\rust\ucsi\ucsi\src\core\units\any.rs:25:9
//! |
//! 25 | panic!("cannot cast si type")
//! | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//! note: inside `<Second as CastFrom<ucsi::ops::Mul<ucsi::ops::Div<ucsi::ops::Div<Meter, Second>, Second>, Kilogram>>>::CAN_CAST_FROM`
//! --> D:\WBH\rust\ucsi\ucsi\src\core\units\any.rs:36:9
//! |
//! 36 | is_same_type_or_panic::<T, B>();
//! | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//! = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
//!
//! note: the above error was encountered while instantiating `fn ucsi::Value::<f64, ucsi::ops::Mul<ucsi::ops::Div<ucsi::ops::Div<ucsi::units::base::Meter, ucsi::units::base::Second>, ucsi::units::base::Second>, ucsi::units::base::Kilogram>>::cast_const::<ucsi::units::base::Second>`
//! --> ucsi-test\tests\test_ops.rs:26:25
//! |
//! 26 | let s_can_never_be_newton: Value<_, s> = force.cast_const();
//! | ^^^^^^^^^^^^^^^^^^
//!
//! For more information about this error, try `rustc --explain E0080`.
//! ```
//!
//! Well, there's probably a little bit of a lot of information that's being reported.
//! Since rust's const evaluation and generic system is still under rapid development,
//! this could be improved in the future.
//!
//! Anyway, at least we can check units at compile time.
//!
//! ## Dive into the library
//!
//! You can find all provided built-in types in the [`units`] module.
//!
//! If you want to create your well-defined special type or associated unit,
//! see the [`macros`] module for some code generator.
//!
//! ## Features
//!
//! ### `no_std` / `no_alloc`
//! This library offers no-std support and no-alloc support.
//!
//! If `no_std` feature is enabled, `String` and `format!` will be exported from `::alloc`.
//!
//! If `no_alloc` feature is enabled, string-based api like `try_cast` and `format_si`
//! cannot be used.
//!
//! ### External crate feature
//!
//! #### `const_soft_float`
//!
//! Disabled by default, included in the `full` feature.
//!
//! This library re-exports the
//! [`const_soft_float`](https://docs.rs/crate/const_soft_float/0.1.4)
//! crate's constant float mathematical operations,
//! and the lib's standard associated units offer constant
//! conversion method for those types.
/// Core module of the library.
/// Internally used fraction representation.
/// Not designed to be soundly used in external codebase.
/// Internally used macros.
/// Not designed to be soundly used in external codebase.
use cfg_if;
// re-export
pub use crate;
pub use crateValue;
pub use crate;
cfg_if!
// feature error