Skip to content

Commit

Permalink
update docs
Browse files Browse the repository at this point in the history
  • Loading branch information
Tehforsch committed Feb 25, 2024
1 parent f6a099e commit 07bfe2d
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 75 deletions.
52 changes: 17 additions & 35 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,11 @@ let time: Time<f64> = 1.0 * seconds;
assert_eq!(format!("{:?}", length / time), "5000 m s^-1")
```

# Design
For example, in order to represent the [SI system of units](https://www.nist.gov/pml/owm/metric-si/si-units), the quantity type would be defined using the `unit_system!` macro as follows:
# Custom unit systems
## The `unit_system` macro
Diman also provides the `unit_system` macro for defining custom
unit systems for everything that is not covered by SI alone.
As an example, consider the following macro call:
```rust
diman::unit_system!(
quantity_type Quantity;
Expand All @@ -178,26 +181,10 @@ diman::unit_system!(
dimension Length;
dimension Time;
dimension Mass;
dimension Temperature;
dimension Current;
dimension AmountOfSubstance;
dimension LuminousIntensity;
);
```
The first two statements imply that the macro should define a `Quantity` type, which is user-facing, and a `Dimension` type, which is used only internally and will surface in compiler error messages.
The macro will automatically implement all the required traits and methods for the `Quantity` type, such that addition and subtraction of two quantities is only allowed for quantities with the same `Dimension` type. During multiplication of two quantities, all the entries of the two dimensions are added. See below for a more comprehensive list of the implemented methods on `Quantity`.

The `unit_system!` macro also allows defining derived dimensions and units:

```rust
diman::unit_system!(
quantity_type Quantity;
dimension_type Dimension;

dimension Length;
dimension Time;

dimension Velocity = Length / Time;
dimension Frequency = 1 / Time;
dimension Energy = Mass * Velocity^2;

#[prefix(kilo, milli)]
#[base(Length)]
Expand All @@ -211,28 +198,23 @@ diman::unit_system!(
unit hours: Time = 3600 * seconds;
unit meters_per_second: Velocity = meters / seconds;
unit kilometers_per_hour: Velocity = kilometers / hours;
constant MY_FAVORITE_VELOCITY = 1000 * kilometers_per_hour;
constant SPEED_OF_LIGHT = 299792458 * meters_per_second;
);


fn fast_enough(x: Length<f64>, t: Time<f64>) {
let vel = x / t;
if vel > 1.0 * MY_FAVORITE_VELOCITY {
println!("{} m/s is definitely fast enough!", vel.value_in(meters_per_second));
}
fn too_fast(x: Length<f64>, t: Time<f64>) -> bool {
x / t > 0.1f64 * SPEED_OF_LIGHT
}

fast_enough(100.0 * kilometers, 0.3 * hours);
too_fast(100.0 * kilometers, 0.3 * hours);
```

Here, `dimension` defines Quantities, which are concrete types, `unit` defines units, which are methods on the corresponding quantities and `constant` defines constants.
Dimensions without a right hand side are base dimensions (such as length, time, mass, temperature, ... in the SI system of units), whereas dimensions with a right hand side are derived dimensions.
The same thing holds for units - every unit is either a base unit for a given base dimension (denoted by the `#[base(...)]` attribute), or derived from base units and other derived units. Base units have the special property that the internal representation of the quantity will be in terms of the base unit (for example, a stored value `1.0` for a quantity with a `Length` dimension corresponds to `meter` in the above definitions).
Other than this, there are no differences between base dimensions and dimensions or base units and units and they can be treated equally in user code.
The macro also accepts more complex expressions such as `dimension Energy = Mass (Length / Time)^2`.
The definitions do not have to be in any specific order.
The macro accepts three different keywords:
1. `dimension` defines a new dimension which is a type. Dimensions without a right hand side are base dimensions (such as `Length` and `Time` in this example), whereas dimensions with a right hand side are derived dimensions (such as `Velocity` in this example).
2. `unit` defines a new units, which are methods on the corresponding quantities and `constant` defines constants. Units without a right-hand side are the base units to one specific base dimension, meaning that they are the unit that will internally be represented with a conversion factor of 1. Base units require the `#[base(...)]` attribute in order to specify which dimension they are the base unit of. Units with a right hand side are derived from other units.
3. `constant` defines a new constant.

# Prefixes
## Prefixes
Unit prefixes can automatically be generated with the `#[prefix(...)]` attribute for unit statements.
For example
```rust
Expand All @@ -244,7 +226,7 @@ unit meters;
will automatically generate the unit `meters` with symbol `m`, as well as `kilometers` and `millimeters` with symbols `km` and `mm` corresponding to `1e3 m` and `1e-3 m`.
For simplicity, the attribute `#[metric_prefixes]` is provided, which will generate all metric prefixes from `atto-` to `exa-` automatically.

# Aliases
## Aliases
Unit aliases can automatically be generated with the `#[alias(...)]` macro. For example
```rust
#[alias(metres)]
Expand Down
58 changes: 18 additions & 40 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,8 +207,11 @@
//! assert_eq!(format!("{:?}", length / time), "5000 m s^-1")
//! ```
//!
//! # Design
//! For example, in order to represent the [SI system of units](https://www.nist.gov/pml/owm/metric-si/si-units), the quantity type would be defined using the `unit_system!` macro as follows:
//! # Custom unit systems
//! ## The `unit_system` macro
//! Diman also provides the `unit_system` macro for defining custom
//! unit systems for everything that is not covered by SI alone.
//! As an example, consider the following macro call:
//! ```
//! # #![allow(incomplete_features)]
//! # #![feature(generic_const_exprs, adt_const_params)]
Expand All @@ -220,30 +223,10 @@
//! dimension Length;
//! dimension Time;
//! dimension Mass;
//! dimension Temperature;
//! dimension Current;
//! dimension AmountOfSubstance;
//! dimension LuminousIntensity;
//! );
//! # }
//! ```
//! The first two statements imply that the macro should define a `Quantity` type, which is user-facing, and a `Dimension` type, which is used only internally and will surface in compiler error messages.
//! The macro will automatically implement all the required traits and methods for the `Quantity` type, such that addition and subtraction of two quantities is only allowed for quantities with the same `Dimension` type. During multiplication of two quantities, all the entries of the two dimensions are added. See below for a more comprehensive list of the implemented methods on `Quantity`.
//!
//! The `unit_system!` macro also allows defining derived dimensions and units:
//!
//! ```
//! # #![allow(incomplete_features)]
//! # #![feature(generic_const_exprs, adt_const_params)]
//! # mod surround {
//! diman::unit_system!(
//! quantity_type Quantity;
//! dimension_type Dimension;
//!
//! dimension Length;
//! dimension Time;
//!
//! dimension Velocity = Length / Time;
//! dimension Frequency = 1 / Time;
//! dimension Energy = Mass * Velocity^2;
//!
//! #[prefix(kilo, milli)]
//! #[base(Length)]
Expand All @@ -257,32 +240,27 @@
//! unit hours: Time = 3600 * seconds;
//! unit meters_per_second: Velocity = meters / seconds;
//! unit kilometers_per_hour: Velocity = kilometers / hours;
//! constant MY_FAVORITE_VELOCITY = 1000 * kilometers_per_hour;
//! constant SPEED_OF_LIGHT = 299792458 * meters_per_second;
//! );
//! # }
//!
//! # use surround::dimensions::{Length, Time, Velocity};
//! # use surround::units::{meters_per_second,kilometers,hours};
//! # use surround::constants::MY_FAVORITE_VELOCITY;
//! # use surround::constants::SPEED_OF_LIGHT;
//!
//! fn fast_enough(x: Length<f64>, t: Time<f64>) {
//! let vel = x / t;
//! if vel > 1.0 * MY_FAVORITE_VELOCITY {
//! println!("{} m/s is definitely fast enough!", vel.value_in(meters_per_second));
//! }
//! fn too_fast(x: Length<f64>, t: Time<f64>) -> bool {
//! x / t > 0.1f64 * SPEED_OF_LIGHT
//! }
//!
//! fast_enough(100.0 * kilometers, 0.3 * hours);
//! too_fast(100.0 * kilometers, 0.3 * hours);
//! ```
//!
//! Here, `dimension` defines Quantities, which are concrete types, `unit` defines units, which are methods on the corresponding quantities and `constant` defines constants.
//! Dimensions without a right hand side are base dimensions (such as length, time, mass, temperature, ... in the SI system of units), whereas dimensions with a right hand side are derived dimensions.
//! The same thing holds for units - every unit is either a base unit for a given base dimension (denoted by the `#[base(...)]` attribute), or derived from base units and other derived units. Base units have the special property that the internal representation of the quantity will be in terms of the base unit (for example, a stored value `1.0` for a quantity with a `Length` dimension corresponds to `meter` in the above definitions).
//! Other than this, there are no differences between base dimensions and dimensions or base units and units and they can be treated equally in user code.
//! The macro also accepts more complex expressions such as `dimension Energy = Mass (Length / Time)^2`.
//! The definitions do not have to be in any specific order.
//! The macro accepts three different keywords:
//! 1. `dimension` defines a new dimension which is a type. Dimensions without a right hand side are base dimensions (such as `Length` and `Time` in this example), whereas dimensions with a right hand side are derived dimensions (such as `Velocity` in this example).
//! 2. `unit` defines a new units, which are methods on the corresponding quantities and `constant` defines constants. Units without a right-hand side are the base units to one specific base dimension, meaning that they are the unit that will internally be represented with a conversion factor of 1. Base units require the `#[base(...)]` attribute in order to specify which dimension they are the base unit of. Units with a right hand side are derived from other units.
//! 3. `constant` defines a new constant.
//!
//! # Prefixes
//! ## Prefixes
//! Unit prefixes can automatically be generated with the `#[prefix(...)]` attribute for unit statements.
//! For example
//! ```
Expand All @@ -303,7 +281,7 @@
//! will automatically generate the unit `meters` with symbol `m`, as well as `kilometers` and `millimeters` with symbols `km` and `mm` corresponding to `1e3 m` and `1e-3 m`.
//! For simplicity, the attribute `#[metric_prefixes]` is provided, which will generate all metric prefixes from `atto-` to `exa-` automatically.
//!
//! # Aliases
//! ## Aliases
//! Unit aliases can automatically be generated with the `#[alias(...)]` macro. For example
//! ```
//! # #![allow(incomplete_features)]
Expand Down

0 comments on commit 07bfe2d

Please sign in to comment.