refactor: (1) Removed useless expressions (2) Applying "cargo fmt"

This commit is contained in:
minagawah
2023-05-14 20:36:32 +09:00
parent a220d0f9f2
commit 49103e8034
15 changed files with 1187 additions and 782 deletions

View File

@@ -1,6 +1,6 @@
[package]
name = "mikaboshi"
version = "0.8.0"
version = "0.8.1"
edition = "2018"
[dependencies]

View File

@@ -1,6 +1,6 @@
MIT License
Copyright (c) 2021 Hiroki Minagawa
Copyright (c) 2023 Hiroki Minagawa
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@@ -175,7 +175,25 @@ You can also explore the actual codes for they contain a lot of _doc tests_.
RUST_BACKTRACE=1 cargo test -vv -- --nocapture
```
## 5. Dislaimer
## 5. Notes
### (1) cargo fmt
Looking into [rustfmt.toml](rustfmt.toml),
you see the setting:
```toml
format_strings = true
```
which works only for the Nightly build.
So, you need:
```bash
cargo +nightly fmt
```
## 6. Dislaimer
There is absolutely no gurantee about the accuracy of the service,
information, or calculated results provided by the program,
@@ -188,6 +206,6 @@ It shall be your own responsibility to ensure the service,
information, or calculated results meet your specific requirements.
## 6. License
## 7. License
MIT license ([LICENSE](LICENSE))

2
rustfmt.toml Normal file
View File

@@ -0,0 +1,2 @@
format_strings = true # default: false
max_width = 54 # default: 100

View File

@@ -1,31 +1,42 @@
//! 八卦 (Ba-Gua) is a concept in 易経 (I-Ching) which is merely a concept
//! in fortune telling, but also appears frequently in a variety of
//! Chinese philosophy. "Gua" (卦) is a conventional unit which characterizes
//! certain aspects/qualities in life. "Ba" simply means "8" in Chinese.
//! So, "Ba-Gua" (八卦) tells that it consists of 8 卦 (Gua). To the eyes of
//! ancient Chinese, everything in this world was of either 陰 (Yin) or 陽 (Yang).
//! Or, you could say, the world is divided into 2. However, if you observe
//! more carefully, you notice some in Yang may slightly lean toward Yin, and
//! some in Yin toward Yang. So, you could probably have another division there,
//! for this time, divisions of 4. For greater Yang, you have lesser "Yin"
//! and "Yang", or you may call them, "Yang-Yang" and "Yang-Yin". Likewise,
//! for Yin, you will have "Yin-Yang" and "Yin-Yin". If you are brave enough,
//! you could repeat the process for the one last time. This time, you would
//! divide the world into 8. For ancient Chinese perceived the last division
//! of 8 being the basic building blocks for observing nature, and called
//! them, 八卦 (Ba-Gua)
//! 八卦 (Ba-Gua) is a concept in 易経 (I-Ching) which
//! is merely a concept in fortune telling, but also
//! appears frequently in a variety of Chinese philosophy.
//! "Gua" (卦) is a conventional unit which characterizes
//! certain aspects/qualities in life. "Ba" simply
//! means "8" in Chinese. So, "Ba-Gua" (八卦) tells
//! that it consists of 8 卦 (Gua). To the eyes of
//! ancient Chinese, everything in this world was of
//! either 陰 (Yin) or 陽 (Yang). Or, you could say,
//! the world is divided into 2. However, if you
//! observe more carefully, you notice some in Yang
//! may slightly lean toward Yin, and some in Yin
//! toward Yang. So, you could probably have another
//! division there, for this time, divisions of 4.
//! For greater Yang, you have lesser "Yin" and "Yang",
//! or you may call them, "Yang-Yang" and "Yang-Yin".
//! Likewise, for Yin, you will have "Yin-Yang" and
//! "Yin-Yin". If you are brave enough, you could
//! repeat the process for the one last time.
//! This time, you would divide the world into 8.
//! For ancient Chinese perceived the last division
//! of 8 being the basic building blocks for observing
//! nature, and called them, 八卦 (Ba-Gua)
//!
//! Now, when we say 八卦 (Ba-Gua), we usually refer to 2 different systems.
//! For the division just described above is called "先天八卦" (or
//! _"The Primordial Heaven"_), and a diagram to represent this order
//! is called "河圖" (He-Tu) (or 伏羲八卦 (Fu-Xi Ba-Gua)). Another one
//! is called "後天八卦" (or _"The Manifested Heaven"_), and its diagram
//! is called "洛書" (Lo-Shu) (or 文王八卦 (King Wen Ba-Gua)).
//! For the former illustrates the world of the original heaven,
//! and the latter, the manifested world (for which elements in nature
//! play active roles to produce gross material plane of our reality).
//! Now, when we say 八卦 (Ba-Gua), we usually refer to
//! 2 different systems. For the division just described
//! above is called "先天八卦" (or _"The Primordial
//! Heaven"_), and a diagram to represent this order
//! is called "河圖" (He-Tu) (or 伏羲八卦 (Fu-Xi Ba-Gua)).
//! Another one is called "後天八卦" (or _"The Manifested
//! Heaven"_), and its diagram is called "洛書" (Lo-Shu)
//! (or 文王八卦 (King Wen Ba-Gua)). For the former
//! illustrates the world of the original heaven, and
//! the latter, the manifested world (for which elements
//! in nature play active roles to produce gross material
//! plane of our reality).
//!
//! Order of 河圖 (He-Tu) (for 先天八卦 _"The Primordial Heaven"_)
//! Order of 河圖 (He-Tu) (for 先天八卦 _"The Primordial
//! Heaven"_)
//!
//! [0] 乾 (Qian)
//! [1] 兌 (Dui)
@@ -36,7 +47,8 @@
//! [6] 坤 (Kun)
//! [7] 艮 (Gen)
//!
//! Order of 洛書 (Lo-Shu) (for 後天八卦 _"The Manifested Heaven"_)
//! Order of 洛書 (Lo-Shu) (for 後天八卦 _"The Manifested
//! Heaven"_)
//!
//! [0] 坎 (Kan)
//! [1] 坤 (Kun)
@@ -47,46 +59,48 @@
//! [6] 艮 (Gen)
//! [7] 離 (Li)
//!
//! So, when we talk about 八卦 (Ba-Gua), we need to be specific about
//! which world we referring to. As you can see, there are 3 sets
//! of vectors defined in this program, namely:
//! So, when we talk about 八卦 (Ba-Gua), we need to be
//! specific about which world we referring to. As you
//! can see, there are 3 sets of vectors defined in this
//! program, namely:
//!
//! - `BAGUA_HE_TU_ORDER`
//! - `BAGUA_LO_SHU_ORDER`
//! - `BAGUA_LO_SHU_ORDER_WITH_CENTER`
//!
//! Notice that the first 2 consists of 8 items, but the third one
//! consists of 9. When using 八卦 (Ba-Gua) for Feng-Shui, we usually
//! refer to 洛書 (Lo-Shu) diagram (which is `BAGUA_LO_SHU_ORDER`).
//! However, we usually plot 洛書 (Lo-Shu) into 9 boxes because it is
//! often associated with 九星 (Jiu-Xing) which requires not only
//! 8 compass directions, but with an extra box in the middle.
//! So, in addition to 八卦 (Ba-Gua), when managing 洛書 (Lo-Shu)
//! for Feng-Shui, we need CENTER (or "中" (Zhong) in Chinese),
//! and that is what we have for `BAGUA_LO_SHU_ORDER_WITH_CENTER`.
//! Notice that the first 2 consists of 8 items, but
//! the third one consists of 9. When using 八卦 (Ba-Gua)
//! for Feng-Shui, we usually refer to 洛書 (Lo-Shu)
//! diagram (which is `BAGUA_LO_SHU_ORDER`). However,
//! we usually plot 洛書 (Lo-Shu) into 9 boxes because
//! it is often associated with 九星 (Jiu-Xing) which
//! requires not only 8 compass directions, but with
//! an extra box in the middle. So, in addition to
//! 八卦 (Ba-Gua), when managing 洛書 (Lo-Shu) for
//! Feng-Shui, we need CENTER (or "中" (Zhong)
//! in Chinese), and that is what we have for
//! `BAGUA_LO_SHU_ORDER_WITH_CENTER`.
//!
//! Also, notice of another vector defined in the program, namely,
//! `BAGUA_LO_SHU_COMPASS_ORDER`. This is a special vector for which
//! the order is _conceptually_ in "Lo-Shu" order, however, mapped
//! to 8 compass directions as each 卦 (Gua) plotted in clockwise manner.
//! This is specially useful when we have an app with a compass UI
//! because you can directly plot 卦 (Gua) out of this vector.
//! Also, notice, another vector defined in
//! the program, `BAGUA_LO_SHU_COMPASS_ORDER`.
//! This is a special vector for which the order is
//! _conceptually_ in "Lo-Shu" order, however, mapped to
//! 8 compass directions as each 卦 (Gua) plotted in
//! clockwise manner. This is specially useful when we
//! have an app with a compass UI because you can
//! directly plot 卦 (Gua) out of this vector.
use serde::{Deserialize, Serialize};
use crate::language::{
Language,
LanguageData,
LanguageTrait,
Language, LanguageData, LanguageTrait,
NameDataTrait,
};
use crate::utils::{
get_json,
make_sort,
};
use crate::utils::{get_json, make_sort};
/// A struct representing 卦 (Gua) and stores its attributes.
/// A struct representing 卦 (Gua) and stores its
/// attributes.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Gua {
pub name: Language,
@@ -95,8 +109,8 @@ pub struct Gua {
pub element: u8,
}
/// A temporary struct for loading JSON data when defining
/// a various vectors for 八卦 (Ba-Gua).
/// A temporary struct for loading JSON data when
/// defining a various vectors for 八卦 (Ba-Gua).
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GuaRaw {
pub name: LanguageData,
@@ -118,14 +132,17 @@ impl NameDataTrait for GuaRaw {
}
lazy_static! {
/// This is a vector for 八卦 (Ba-Gua) with 9 items where the 5th item
/// being "中" (Zhong). By having 9 items instead of 8, it can be
/// directly mapped to 9 stars of 九星 (Jiu-Xing). Since 九星 (Jiu-Xing)
/// is mapped in "Lo-Shu" (洛書) order, so is this vector.
/// Check out the attribute `jiuxing_num` for each data, and you will
/// notice it corresponds to the Jiu-Xing number.
/// This is a vector for 八卦 (Ba-Gua) with 9 items
/// where the 5th item being "中" (Zhong). By having
/// 9 items instead of 8, it can be directly mapped
/// to 9 stars of 九星 (Jiu-Xing). Since 九星
/// (Jiu-Xing) is mapped in "Lo-Shu" (洛書) order,
/// so is this vector. Check out the attribute
/// `jiuxing_num` for each data, and you will notice
/// it corresponds to the Jiu-Xing number.
///
/// 八卦 (Ba-Gua) in "Lo-Shu" (洛書) order with 中 (Zhong) in the middle:
/// 八卦 (Ba-Gua) in "Lo-Shu" (洛書) order with
/// 中 (Zhong) in the middle:
///
/// [0] 坎 (Kan) -> No. 1
/// [1] 坤 (Kun) -> No. 2
@@ -137,7 +154,8 @@ lazy_static! {
/// [7] 艮 (Gen) -> No. 8
/// [8] 離 (Li) -> No. 9
///
/// For attributes details stored in the vector is found in JSON file:
/// For attributes details stored in the vector is
/// found in JSON file:
/// `src/json/bagua.json`
pub static ref BAGUA_LO_SHU_ORDER_WITH_CENTER: Vec<Gua> = {
let json = &include_str!("../json/bagua.json");
@@ -156,7 +174,8 @@ lazy_static! {
/// [INDEX] 八卦 (Ba-Gua) in "He-Tu" (河圖) order.
pub static ref BAGUA_HE_TU_ORDER_INDEXES: Vec<u8> = vec![0, 1, 2, 3, 5, 6, 7, 8];
/// [ACTUAL DATA] 八卦 (Ba-Gua) in "He-Tu" (河圖) order.
/// [ACTUAL DATA] 八卦 (Ba-Gua) in "He-Tu" (河圖)
/// order.
///
/// [0] 乾 (Qian)
/// [1] 兌 (Dui)
@@ -175,7 +194,8 @@ lazy_static! {
/// [INDEX] 八卦 (Ba-Gua) in "Lo-Shu" (洛書) order.
pub static ref BAGUA_LO_SHU_ORDER_INDEXES: Vec<u8> = vec![0, 1, 2, 3, 5, 6, 7, 8];
/// [ACTUAL DATA] 八卦 (Ba-Gua) in "Lo-Shu" (洛書) order.
/// [ACTUAL DATA] 八卦 (Ba-Gua) in "Lo-Shu" (洛書)
/// order.
///
/// [0] 坎 (Kan)
/// [1] 艮 (Gen)
@@ -191,16 +211,22 @@ lazy_static! {
BAGUA_LO_SHU_ORDER_WITH_CENTER.to_vec() // data source
);
/// [INDEX] 八卦 (Ba-Gua) in "Lo-Shu" order, however, mapped to 8 compass directions.
/// [INDEX] 八卦 (Ba-Gua) in "Lo-Shu" order, however,
/// mapped to 8 compass directions.
pub static ref BAGUA_LO_SHU_COMPASS_ORDER_INDEXES: Vec<u8> = vec![0, 7, 2, 3, 8, 1, 6, 5];
/// [ACTUAL DATA] 八卦 (Ba-Gua) in "Lo-Shu" order, however, mapped to 8 compass directions.
/// When "Lo-Shu" (洛書) order is mapped to 8 compass directions, it is convenient
/// to have a vector which starts with 卦 (Gua) for _"NORTH"_ which is "坎" (Kan).
/// Likewise, we want the second item being 卦 (Gua) for _"NORTH EAST"_ which is "艮" (Gen).
/// For the third item, likewise, for _"EAST"_ or "震" (Zhen).
/// [ACTUAL DATA] 八卦 (Ba-Gua) in "Lo-Shu" order,
/// however, mapped to 8 compass directions. When
/// "Lo-Shu" (洛書) order is mapped to 8 compass
/// directions, it is convenient to have a vector
/// which starts with 卦 (Gua) for _"NORTH"_ which
/// is "坎" (Kan). Likewise, we want the second
/// item being 卦 (Gua) for _"NORTH EAST"_ which is
/// "艮" (Gen). For the third item, likewise, for
/// _"EAST"_ or "震" (Zhen).
///
/// 八卦 (Ba-Gua) in "Lo-Shu" order mapped to 8 directions (starting NORTH):
/// 八卦 (Ba-Gua) in "Lo-Shu" order mapped to
/// 8 directions (starting NORTH):
///
/// [0] 坎 (Kan)
/// [1] 艮 (Gen)
@@ -230,7 +256,9 @@ lazy_static! {
/// JsValue::from_serde(&gua).unwrap()
/// }
/// ```
pub fn get_gua_compass_order(index: usize) -> Option<&'static Gua> {
pub fn get_gua_compass_order(
index: usize,
) -> Option<&'static Gua> {
match BAGUA_LO_SHU_COMPASS_ORDER.get(index) {
Some(gua) => Some(gua),
None => None,
@@ -243,7 +271,11 @@ mod tests {
#[test]
fn test_constant_bagua_list_full() {
assert_eq!(BAGUA_LO_SHU_ORDER_WITH_CENTER[0].jiuxing_num, 1);
assert_eq!(
BAGUA_LO_SHU_ORDER_WITH_CENTER[0]
.jiuxing_num,
1
);
}
// TODO: BAGUA_LO_SHU_COMPASS_ORDER_INDEXES

View File

@@ -1,19 +1,18 @@
//! A module for compass directions. When dividing 360 degrees into 8,
//! we get 45 degrees. Ancient Chinese further divided them each into 3
//! (called "sectors"), each having 15 degrees. Meaning, there are
//! 24 sectors as a total. This is called, 二十四山向 (Er-Shi-Si Shan-Xiang).
//! Not only for 8 directions, but these 24 directions (sectors)
//! are used in Feng-Shui, and this is the module for these directions.
//! A module for compass directions. When dividing 360
//! degrees into 8, we get 45 degrees. Ancient Chinese
//! further divided them each into 3 (called "sectors"),
//! each having 15 degrees. Meaning, there are 24 sectors
//! as a total. This is called, 二十四山向 (Er-Shi-Si
//! Shan-Xiang). Not only for 8 directions, but these
//! 24 directions (sectors) are used in Feng-Shui, and
//! this is the module for these directions.
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use crate::bagua::{Gua, BAGUA_LO_SHU_ORDER_WITH_CENTER};
use crate::ganzhi::{
Branch,
Stem,
BRANCHES,
STEMS,
use crate::bagua::{
Gua, BAGUA_LO_SHU_ORDER_WITH_CENTER,
};
use crate::ganzhi::{Branch, Stem, BRANCHES, STEMS};
/// 二十四山向 (Er-Shi-Si Shan-Xiang) can be
/// either 卦 (Gua), 干 (Gan), or 支 (Zhi).
@@ -25,14 +24,19 @@ pub enum TwentyFourType<'a> {
/// A struct representing compass direction.
/// For each direction, there are 3 sectors.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[derive(
Debug, Clone, PartialEq, Serialize, Deserialize,
)]
pub struct Direction {
pub direction: String,
pub sector: usize,
}
impl Direction {
pub fn new(direction: &str, sector: usize) -> Direction {
pub fn new(
direction: &str,
sector: usize,
) -> Direction {
Direction {
direction: direction.to_string(),
sector,
@@ -41,26 +45,29 @@ impl Direction {
}
/// An array for 8 directions.
pub const DIRECTIONS: [&str; 8] = ["n", "ne", "e", "se", "s", "sw", "w", "nw"];
pub const DIRECTIONS: [&str; 8] =
["n", "ne", "e", "se", "s", "sw", "w", "nw"];
lazy_static! {
/// A hash map with 9 items.
/// Say, we have 9 boxes displayed on a device screen.
/// Except for the box in the middle, we have 8 boxes
/// around the middle to represent 8 compass directions.
/// When facing "n" (north), for the first row,
/// we have "nw", "n", and "ne". For the second row,
/// we have "w", "", and "e" (where "" being the middle box).
/// For the last, we have "sw", "s", and "se".
/// Say, we have 9 boxes displayed on a device
/// screen. Except for the box in the middle, we
/// have 8 boxes around the middle to represent
/// 8 compass directions. When facing "n" (north),
/// for the first row, we have "nw", "n", and "ne".
/// For the second row, we have "w", "", and "e"
/// (where "" being the middle box). For the last,
/// we have "sw", "s", and "se".
///
/// [0] nw [1] n [2] ne
/// [3] w [4] [5] e
/// [6] sw [7] s [8] se
///
/// Now, consider when the device rotates.
/// Depending on which direction the device is facing,
/// we have different labels. For all 8 directions,
/// this HashMap provides a map for the positions.
/// Depending on which direction the device is
/// facing, we have different labels. For all
/// 8 directions, this HashMap provides a map for
/// the positions.
pub static ref DIRECTION_POSITIONS_IN_CHART: HashMap<&'static str, [&'static str; 9]> = [
("n", ["nw", "n", "ne", "w", "", "e", "sw", "s", "se"]),
("ne", ["n", "ne", "e", "nw", "", "se", "w", "sw", "s"]),
@@ -93,7 +100,9 @@ lazy_static! {
/// )
/// }
/// ```
pub fn get_direction_positions_in_chart(direction: &str) -> Option<&[&str; 9]> {
pub fn get_direction_positions_in_chart(
direction: &str,
) -> Option<&[&str; 9]> {
DIRECTION_POSITIONS_IN_CHART.get(direction)
}
@@ -133,25 +142,27 @@ pub fn get_opposite_direction(dir: &str) -> &str {
OPPOSITE_DIRECTION[dir]
}
/// An array with 24 items. Imagine having a circlar disc displayed
/// on a device screen. When dividing 360 by 8 directions, we get
/// 45 degrees for each. When each direction is further divided
/// into 3, then each is called a "sector", and it has 15 degrees
/// for each "sector". Sectors are placed in clockwise order
/// An array with 24 items. Imagine having a circlar
/// disc displayed on a device screen. When dividing 360
/// by 8 directions, we get 45 degrees for each. When
/// each direction is further divided into 3, then each
/// is called a "sector", and it has 15 degrees for each
/// "sector". Sectors are placed in clockwise order
/// (left to right) for each direction, so that you see
/// the sector 1 being placed on your very left. Then, you see
/// the sector 2 in the middle, and the sector 3 on your right.
/// Imagine the device pointing north. On the circular disc,
/// what you see at the very top is the sector 2 of "N" (north),
/// denoted as "N2". On your left, you see "N1".
/// On your right, "N3".
/// the sector 1 being placed on your very left. Then,
/// you see the sector 2 in the middle, and the sector 3
/// on your right. Imagine the device pointing north.
/// On the circular disc, what you see at the very top
/// is the sector 2 of "N" (north), denoted as "N2".
/// On your left, you see "N1". On your right, "N3".
///
/// When we want to express all the 24 sectors, we want
/// an array with 24 items. For the first item in the array [0],
/// it is convenient to have "N2". Then, for the second item
/// in the array [1], we want "N3". For [2], we want "NE1".
/// For [3], we want "NE2". And, so on. As you can imagine,
/// "N1" comes to the very last in the array, or [23].
/// an array with 24 items. For the first item in the
/// array [0], it is convenient to have "N2". Then, for
/// the second item in the array [1], we want "N3".
/// For [2], we want "NE1". For [3], we want "NE2".
/// And, so on. As you can imagine, "N1" comes to the
/// very last in the array, or [23].
pub const TWENTYFOUR_SECTORS: [u8; 24] = [
2, // 0: n
3, // 1: n
@@ -221,7 +232,9 @@ lazy_static! {
/// JsValue::from_serde(dir).unwrap()
/// }
/// ```
pub fn get_twentyfour_direction_from_index(index: usize) -> &'static Direction {
pub fn get_twentyfour_direction_from_index(
index: usize,
) -> &'static Direction {
&TWENTYFOUR_INDEX_TO_DIRECTIONS[index]
}
@@ -245,11 +258,15 @@ lazy_static! {
.collect();
}
/// An array with 24 items, each being a tuple. For each tuple,
/// the first represents the type of 二十四山向 (Er-Shi-Si Shan-Xiang),
/// and the second is the index of the type.
/// The type being: [0] BAGUA, [1] STEM, or [2] BRANCH.
pub const TWENTYFOUR_ORDER_START_NORTH: [(usize, usize); 24] = [
/// An array with 24 items, each being a tuple.
/// For each tuple, the first represents the type of
/// 二十四山向 (Er-Shi-Si Shan-Xiang), and the second
/// is the index of the type. The type being:
/// [0] BAGUA, [1] STEM, or [2] BRANCH.
pub const TWENTYFOUR_ORDER_START_NORTH: [(
usize,
usize,
); 24] = [
(2, 0), // 0: [0] 子
(1, 9), // 1: [9] 癸
(2, 1), // 2: [1] 丑
@@ -276,7 +293,8 @@ pub const TWENTYFOUR_ORDER_START_NORTH: [(usize, usize); 24] = [
(1, 8), // 23: [8] 壬
];
/// From index, simply returns the corresponding `TwentyFourType`.
/// From index, simply returns the corresponding
/// `TwentyFourType`.
///
/// Example:
/// ```rust
@@ -293,12 +311,19 @@ pub const TWENTYFOUR_ORDER_START_NORTH: [(usize, usize); 24] = [
/// }
/// }
/// ```
pub fn get_twentyfour_data_from_index(index: usize) -> TwentyFourType<'static> {
let (t_type, t_index) = TWENTYFOUR_ORDER_START_NORTH[index];
pub fn get_twentyfour_data_from_index(
index: usize,
) -> TwentyFourType<'static> {
let (t_type, t_index) =
TWENTYFOUR_ORDER_START_NORTH[index];
match t_type {
0 => TwentyFourType::Gua(&BAGUA_LO_SHU_ORDER_WITH_CENTER[t_index]),
0 => TwentyFourType::Gua(
&BAGUA_LO_SHU_ORDER_WITH_CENTER[t_index],
),
1 => TwentyFourType::Stem(&STEMS[t_index]),
2 => TwentyFourType::Branch(&BRANCHES[t_index]),
2 => {
TwentyFourType::Branch(&BRANCHES[t_index])
}
_ => panic!("Unknown type: {}", t_type),
}
}
@@ -307,7 +332,8 @@ pub fn get_twentyfour_data_from_index(index: usize) -> TwentyFourType<'static> {
// From **DEGREES**
// ===========================================================
/// From the given degrees, returns the corresponding `Direction`.
/// From the given degrees, returns the corresponding
/// `Direction`.
///
/// Example:
/// ```rust
@@ -320,7 +346,9 @@ pub fn get_twentyfour_data_from_index(index: usize) -> TwentyFourType<'static> {
/// JsValue::from_serde(&dir).unwrap()
/// }
/// ```
pub fn get_twentyfour_direction_from_degrees(d: f32) -> Direction {
pub fn get_twentyfour_direction_from_degrees(
d: f32,
) -> Direction {
if !(7.5..352.5).contains(&d) {
// d >= 352.5 || d < 7.5
Direction::new("n", 2)
@@ -378,15 +406,23 @@ pub fn get_twentyfour_direction_from_degrees(d: f32) -> Direction {
// From **DIRECTION**
// ===========================================================
/// From the given direction and sector, finds the corresponding index
/// in `TWENTYFOUR_DIRECTIONS_TO_INDEX`
pub fn get_twentyfour_index_from_direction(direction: &str, sector: usize) -> usize {
/// From the given direction and sector, finds the
/// corresponding index in
/// `TWENTYFOUR_DIRECTIONS_TO_INDEX`
pub fn get_twentyfour_index_from_direction(
direction: &str,
sector: usize,
) -> usize {
*TWENTYFOUR_DIRECTIONS_TO_INDEX
.get(format!("{}{}", direction, sector).as_str())
.get(
format!("{}{}", direction, sector)
.as_str(),
)
.unwrap()
}
/// From the given direction and sector, returns `TwentyFourType`.
/// From the given direction and sector, returns
/// `TwentyFourType`.
///
/// Example:
/// ```rust
@@ -407,12 +443,23 @@ pub fn get_twentyfour_data_from_direction(
direction: &str,
sector: usize,
) -> TwentyFourType<'static> {
get_twentyfour_data_from_index(get_twentyfour_index_from_direction(direction, sector))
get_twentyfour_data_from_index(
get_twentyfour_index_from_direction(
direction, sector,
),
)
}
/// From the given direction and sector, returns `Direction`.
pub fn get_twentyfour_direction_from_direction(direction: &str, sector: usize) -> &Direction {
&TWENTYFOUR_INDEX_TO_DIRECTIONS[get_twentyfour_index_from_direction(direction, sector)]
/// From the given direction and sector, returns
/// `Direction`.
pub fn get_twentyfour_direction_from_direction(
direction: &str,
sector: usize,
) -> &Direction {
&TWENTYFOUR_INDEX_TO_DIRECTIONS
[get_twentyfour_index_from_direction(
direction, sector,
)]
}
#[cfg(test)]
@@ -424,8 +471,15 @@ mod tests {
#[test]
fn test_get_direction_positions_in_chart() {
let exp = ["nw", "n", "ne", "w", "", "e", "sw", "s", "se"];
assert_eq!(get_direction_positions_in_chart("n").unwrap(), &exp);
let exp = [
"nw", "n", "ne", "w", "", "e", "sw", "s",
"se",
];
assert_eq!(
get_direction_positions_in_chart("n")
.unwrap(),
&exp
);
}
// TODO: OPPOSITE_DIRECTION
@@ -433,7 +487,8 @@ mod tests {
// TODO: TWENTYFOUR_SECTORS
#[test]
fn test_constant_twentyfour_index_to_directions() {
fn test_constant_twentyfour_index_to_directions()
{
assert_eq!(
TWENTYFOUR_INDEX_TO_DIRECTIONS[0],
Direction {
@@ -449,12 +504,21 @@ mod tests {
direction: String::from("n"),
sector: 2,
};
assert_eq!(get_twentyfour_direction_from_index(0), &exp);
assert_eq!(
get_twentyfour_direction_from_index(0),
&exp
);
}
#[test]
fn test_constant_twentyfour_directions_to_index() {
assert_eq!(*TWENTYFOUR_DIRECTIONS_TO_INDEX.get("n2").unwrap(), 0_usize);
fn test_constant_twentyfour_directions_to_index()
{
assert_eq!(
*TWENTYFOUR_DIRECTIONS_TO_INDEX
.get("n2")
.unwrap(),
0_usize
);
}
// Only for test
@@ -471,13 +535,16 @@ mod tests {
#[test]
fn test_get_twentyfour_data_from_index() {
assert!(get_twentyfour_data_from_index(0).is_branch());
assert!(get_twentyfour_data_from_index(0)
.is_branch());
}
#[test]
fn test_get_twentyfour_direction_from_degrees() {
assert_eq!(
get_twentyfour_direction_from_degrees(0_f32),
get_twentyfour_direction_from_degrees(
0_f32
),
Direction {
direction: String::from("n"),
sector: 2,

View File

@@ -1,10 +1,13 @@
//! Based on 5 elements in nature with its 陰 (Yin) and 陽 (Yang) for each,
//! ancient Chinese described the plant growth using 10 conventional symbols
//! known as "10 Gan" (十干). Also, they tracked the motion of Jupiter
//! (which has 12 year cycle) and so they did divided the night sky into 12 regions,
//! and this is known as "12 Zhi" (十二支). When they record time and space,
//! they used the combinations of 10 Gan (干) and 12 Zhi (支)
//! which makes 60 patterns, and this is called 干支 (Gan-Zhi).
//! Based on 5 elements in nature with its 陰 (Yin) and
//! 陽 (Yang) for each, ancient Chinese described the
//! plant growth using 10 conventional symbols known as
//! "10 Gan" (十干). Also, they tracked the motion of
//! Jupiter (which has 12 year cycle) and so they did
//! divided the night sky into 12 regions, and this is
//! known as "12 Zhi" (十二支). When they record time
//! and space, they used the combinations of 10 Gan (干)
//! and 12 Zhi (支) which makes 60 patterns, and this
//! is called 干支 (Gan-Zhi).
//!
//! 10 Gan (干):
//!
@@ -34,66 +37,56 @@
//! [10] 戌 (Xu)
//! [11] 亥 (Hai)
use chrono::naive::{NaiveDate, NaiveTime};
use chrono::offset::{FixedOffset, Utc};
use chrono::{DateTime, Datelike, Timelike};
use serde::{Deserialize, Serialize};
use chrono::{
DateTime,
Datelike,
Timelike,
};
use chrono::offset::{
Utc,
FixedOffset,
};
use chrono::naive::{
NaiveDate,
NaiveTime,
};
use sowngwala::time::{
julian_day_from_generic_date,
julian_day_from_generic_datetime,
modified_julian_day_from_generic_datetime,
naive_date_from_generic_datetime,
naive_time_from_generic_datetime,
utc_from_fixed,
naive_time_from_generic_datetime, utc_from_fixed,
};
use crate::language::{
Language,
LanguageData,
LanguageTrait,
Language, LanguageData, LanguageTrait,
NameDataTrait,
};
use crate::solar_terms::get_lichun;
use crate::utils::{
get_json,
longitude_of_the_sun_from_generic_date,
get_json, longitude_of_the_sun_from_generic_date,
};
/// A struct representing 干 (Gan) or "Stem" and stores its attributes.
/// A struct representing 干 (Gan) or "Stem" and stores
/// its attributes.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Stem {
pub num: u8,
pub name: Language,
}
/// A struct representing 支 (Zhi) or "Branch" and stores its attributes.
/// A struct representing 支 (Zhi) or "Branch" and
/// stores its attributes.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Branch {
pub num: u8,
pub name: Language,
}
/// A temporary struct for loading JSON data when defining a static const `STEMS`.
/// A temporary struct for loading JSON data when
/// defining a static const `STEMS`.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StemRawData {
pub num: u8,
pub name: LanguageData,
}
/// A temporary struct for loading JSON data when defining a static const `BRANCHES`.
/// A temporary struct for loading JSON data when
/// defining a static const `BRANCHES`.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BranchRawData {
pub num: u8,
@@ -112,17 +105,19 @@ impl NameDataTrait for BranchRawData {
}
}
/// A struct for holding `Stem` and `Branch`, or denoted as 干支 (Gan-Zhi).
/// A struct for holding `Stem` and `Branch`, or denoted
/// as 干支 (Gan-Zhi).
#[derive(Debug, Serialize)]
pub struct GanZhi<'a> {
pub stem: &'a Stem,
pub branch: &'a Branch,
}
/// A struct representing 八字 (Bazi) and stores `GanZhi` as its attributes.
/// It is referred as "The Four Pillars of Destiny" in English
/// mainly because the structure of 八字 (Bazi) necessary
/// for divinations in 四柱命理学 (_"The Four Pillars of Destiny"_).
/// A struct representing 八字 (Bazi) and stores `GanZhi`
/// as its attributes. It is referred as "The Four
/// Pillars of Destiny" in English mainly because the
/// structure of 八字 (Bazi) necessary for divinations
/// in 四柱命理学 (_"The Four Pillars of Destiny"_).
#[derive(Debug, Serialize)]
pub struct Bazi<'a> {
pub year: GanZhi<'a>,
@@ -144,22 +139,37 @@ impl LanguageTrait for Branch {
}
impl GanZhi<'_> {
/// Concatenate Stem & Branch (for Chinese characters)
/// Concatenate Stem & Branch (for Chinese
/// characters)
#[allow(dead_code)]
fn alphabet(&self) -> String {
format!("{}{}", self.stem.alphabet(), self.branch.alphabet())
format!(
"{}{}",
self.stem.alphabet(),
self.branch.alphabet()
)
}
/// Concatenate Stem & Branch (for Chinese phonetics)
/// Concatenate Stem & Branch (for Chinese
/// phonetics)
#[allow(dead_code)]
fn phonetic(&self) -> String {
format!("{} {}", self.stem.phonetic(), self.branch.phonetic())
format!(
"{} {}",
self.stem.phonetic(),
self.branch.phonetic()
)
}
/// Concatenate Stem & Branch (for Japanese characters)
/// Concatenate Stem & Branch (for Japanese
/// characters)
#[allow(dead_code)]
fn alphabet_ja(&self) -> String {
format!("{}{}", self.stem.alphabet_ja(), self.branch.alphabet_ja())
format!(
"{}{}",
self.stem.alphabet_ja(),
self.branch.alphabet_ja()
)
}
}
@@ -178,7 +188,8 @@ impl<'a> Bazi<'a> {
}
}
/// Returns `Bazi` from localtime (`DateTime`) and zone (`i8`).
/// Returns `Bazi` from localtime (`DateTime`) and
/// zone (`i8`).
///
/// Example:
/// ```rust
@@ -202,35 +213,52 @@ impl<'a> Bazi<'a> {
/// ).unwrap()
/// }
/// ```
pub fn from_fixed(fixed: DateTime<FixedOffset>) -> Bazi<'a> {
pub fn from_fixed(
fixed: DateTime<FixedOffset>,
) -> Bazi<'a> {
let utc = utc_from_fixed(fixed);
let year = get_year_ganzhi(utc);
let month = get_month_ganzhi(Box::new(utc), year.stem.num);
let month = get_month_ganzhi(
Box::new(utc),
year.stem.num,
);
let day = get_day_ganzhi(Box::new(utc));
let hour = get_hour_ganzhi(
Box::new(
naive_time_from_generic_datetime(fixed)
naive_time_from_generic_datetime(
fixed,
),
day.stem.num
),
day.stem.num,
);
Bazi::new(year, month, day, hour)
}
pub fn from_utc(utc: DateTime<Utc>, t: NaiveTime) -> Bazi<'a> {
pub fn from_utc(
utc: DateTime<Utc>,
t: NaiveTime,
) -> Bazi<'a> {
let year = get_year_ganzhi(utc);
let month = get_month_ganzhi(Box::new(utc), year.stem.num);
let month = get_month_ganzhi(
Box::new(utc),
year.stem.num,
);
let day = get_day_ganzhi(Box::new(utc));
let hour = get_hour_ganzhi(Box::new(t), day.stem.num);
let hour = get_hour_ganzhi(
Box::new(t),
day.stem.num,
);
Bazi::new(year, month, day, hour)
}
}
lazy_static! {
/// A static vector with 60 items. `Vec<usize, usize>` where the first
/// `usize` being the `STEMS` index, and the second for the `BRANCHES`.
/// It is simply the combination of 10 stems and 12 branches
/// A static vector with 60 items. `Vec<usize, usize>`
/// where the first `usize` being the `STEMS` index,
/// and the second for the `BRANCHES`. It is simply
/// the combination of 10 stems and 12 branches
/// which eventually adds up to 60 patterns.
pub static ref GANZHI_SEXAGESIMAL: Vec<(usize, usize)> = {
let mut v = vec![];
@@ -242,8 +270,9 @@ lazy_static! {
v
};
/// A static vector with 10 items, each represents 干 (Gan).
/// Each stores associated attributes for the 干 (Gan).
/// A static vector with 10 items, each represents
/// 干 (Gan). Each stores associated attributes for
/// the 干 (Gan).
///
/// [0] 甲 (Jia)
/// [1] 乙 (Yi)
@@ -256,7 +285,8 @@ lazy_static! {
/// [8] 壬 (Ren)
/// [9] 癸 (Gui)
///
/// For attributes details stored in the vector is found in JSON file:
/// For attributes details stored in the vector is
/// found in JSON file:
/// `src/json/ganzhi_stems.json`
pub static ref STEMS: Vec<Stem> = {
let json = &include_str!("../json/ganzhi_stems.json");
@@ -270,8 +300,9 @@ lazy_static! {
}).collect()
};
/// A static vector with 10 items, each represents 支 (Zhi).
/// Each stores associated attributes for the 支 (Zhi).
/// A static vector with 10 items, each represents 支
/// (Zhi). Each stores associated attributes for the
/// 支 (Zhi).
///
/// [0] 子 (Zi)
/// [1] 丑 (Chou)
@@ -301,15 +332,16 @@ lazy_static! {
};
/// This is a table used when finding "Hour Stem".
/// Columns represents "Day Stem" groups, and there are 5 groups.
/// For insntace, if you have 甲 for "Day Stem",
/// you are looking into the first column (group).
/// Rows represents "Hour Branches" for which there are 12.
/// For instance, if you have 子 for "Hour Branch",
/// you are looking into the first row.
/// So, when you have 甲 for "Day Stem",
/// and 子 for "Hour Branch", "Hour Stem" is located
/// in the first column in the first row, which is 甲.
/// Columns represents "Day Stem" groups, and
/// there are 5 groups. For insntace, if you have
/// 甲 for "Day Stem", you are looking into the
/// first column (group). Rows represents "Hour
/// Branches" for which there are 12. For instance,
/// if you have 子 for "Hour Branch", you are
/// looking into the first row. So, when you have
/// 甲 for "Day Stem", and 子 for "Hour Branch",
/// "Hour Stem" is located in the first column in
/// the first row, which is 甲.
///
/// &nbsp; &nbsp; &nbsp; 甲乙丙丁戊
/// &nbsp; &nbsp; &nbsp; 己庚辛壬癸
@@ -355,13 +387,14 @@ lazy_static! {
}
/// Year Ganzhi
fn get_year_ganzhi(utc: DateTime<Utc>) -> GanZhi<'static> {
fn get_year_ganzhi(
utc: DateTime<Utc>,
) -> GanZhi<'static> {
// Year Stem and Branch are easily found.
// However, we must watch out if it is before
// or after Lichun. The year begins from Lichun,
// and it belongs to last year if the date
// is before Lichun.
let lichun: NaiveDate = get_lichun(utc.year());
let year: i32 =
@@ -402,12 +435,15 @@ fn get_month_ganzhi(
) -> GanZhi<'static> {
let utc = *utc;
let lng: f64 = longitude_of_the_sun_from_generic_date(
naive_date_from_generic_datetime(utc)
let lng: f64 =
longitude_of_the_sun_from_generic_date(
naive_date_from_generic_datetime(utc),
);
// Branch is easily found by looking at the longitude of the sun.
let branch_index: usize = if (315.0..345.0).contains(&lng) {
// Branch is easily found by looking at the
// longitude of the sun.
let branch_index: usize =
if (315.0..345.0).contains(&lng) {
0 // 立春 (lichun) + 雨水 (yushui) ---> 寅 (yin)
} else if !(15.0..345.0).contains(&lng) {
1 // 啓蟄 (jingzhe) + 春分 (chunfen) ---> 卯 (mao)
@@ -434,38 +470,51 @@ fn get_month_ganzhi(
11 // 小寒 (xiaohan) + 大寒 (dahan) ---> 丑 (chou)
};
// Stem is found using the Year Stem.
// For a given year, you can find the first Month Stem.
// Once you find the first Month Stem,
// you simply count up to the current month.
// This is done by adding 'branch_id' because 'branch_id'
// is nothing but how many month from the beginning (Lichun).
let stem_index: usize = if year_stem_num == 1 || year_stem_num == 6 {
// Stem is found using the Year Stem. For a given
// year, you can find the first Month Stem. Once
// you find the first Month Stem, you simply count
// up to the current month. This is done by adding
// 'branch_id' because 'branch_id' is nothing but
// how many month from the beginning (Lichun).
let stem_index: usize = if year_stem_num == 1
|| year_stem_num == 6
{
2 // 甲(jia:1) or 己(ji:6) ---> 丙(bing:3)
} else if year_stem_num == 2 || year_stem_num == 7 {
} else if year_stem_num == 2 || year_stem_num == 7
{
4 // 乙(yi:2) or 庚(geng:7) ---> 戊(wu:5)
} else if year_stem_num == 3 || year_stem_num == 8 {
} else if year_stem_num == 3 || year_stem_num == 8
{
6 // 丙(bing:3) or 辛(xin:8) ---> 庚(geng:7)
} else if year_stem_num == 4 || year_stem_num == 9 {
} else if year_stem_num == 4 || year_stem_num == 9
{
8 // 丁(ding:4) or 壬(ren:9) ---> 壬(ren:9)
} else {
0 // 戊(wu:5) or 癸(gui:10) ---> 甲(jia:1)
};
GanZhi {
stem: &STEMS[(stem_index + branch_index) % 10],
stem: &STEMS
[(stem_index + branch_index) % 10],
branch: &BRANCHES[(branch_index + 2) % 12],
}
}
/// Day Ganzhi
#[allow(clippy::boxed_local)]
fn get_day_ganzhi(utc: Box<DateTime<Utc>>) -> GanZhi<'static> {
fn get_day_ganzhi(
utc: Box<DateTime<Utc>>,
) -> GanZhi<'static> {
let utc = *utc;
let mjd: f64 = modified_julian_day_from_generic_datetime(utc);
let index = ((mjd - 10.0) % 60.0).floor() as usize;
let mjd: f64 =
modified_julian_day_from_generic_datetime(
utc,
);
let index =
((mjd - 10.0) % 60.0).floor() as usize;
let (stem_id, branch_id) = GANZHI_SEXAGESIMAL[index];
let (stem_id, branch_id) =
GANZHI_SEXAGESIMAL[index];
GanZhi {
stem: &STEMS[stem_id],
@@ -475,9 +524,14 @@ fn get_day_ganzhi(utc: Box<DateTime<Utc>>) -> GanZhi<'static> {
/// Hour Ganzhi
#[allow(clippy::boxed_local)]
fn get_hour_ganzhi(t: Box<NaiveTime>, day_stem_num: u8) -> GanZhi<'static> {
// The branch is easily found by looking at the hour range of the day.
let branch_id: usize = if t.hour() == 23 || t.hour() == 0 {
fn get_hour_ganzhi(
t: Box<NaiveTime>,
day_stem_num: u8,
) -> GanZhi<'static> {
// The branch is easily found by looking at the
// hour range of the day.
let branch_id: usize =
if t.hour() == 23 || t.hour() == 0 {
0
} else if t.hour() < 3 {
1
@@ -503,10 +557,12 @@ fn get_hour_ganzhi(t: Box<NaiveTime>, day_stem_num: u8) -> GanZhi<'static> {
11 // if t.hour() <= 22
};
// The stem is found by looking at a special table.
// Read comments for 'HOUR_STEM_TABLE' for details.
let group_id: usize = if day_stem_num == 1 || day_stem_num == 6 {
// The stem is found by looking at a special
// table. Read comments for 'HOUR_STEM_TABLE' for
// details.
let group_id: usize = if day_stem_num == 1
|| day_stem_num == 6
{
0
} else if day_stem_num == 2 || day_stem_num == 7 {
1
@@ -518,7 +574,8 @@ fn get_hour_ganzhi(t: Box<NaiveTime>, day_stem_num: u8) -> GanZhi<'static> {
4 // day_stem_num == 5 || day_stem_num == 10
};
let stem_id: usize = HOUR_STEM_TABLE[branch_id][group_id];
let stem_id: usize =
HOUR_STEM_TABLE[branch_id][group_id];
GanZhi {
stem: &STEMS[stem_id],
@@ -529,10 +586,7 @@ fn get_hour_ganzhi(t: Box<NaiveTime>, day_stem_num: u8) -> GanZhi<'static> {
#[cfg(test)]
mod tests {
use super::*;
use sowngwala::time::{
build_fixed,
build_utc,
};
use sowngwala::time::{build_fixed, build_utc};
// TODO: GANZHI_SEXAGESIMAL
@@ -555,7 +609,8 @@ mod tests {
let fixed: DateTime<FixedOffset> =
build_fixed(
2021, 7, 6, 14, 57, 17, nanosecond, zone,
2021, 7, 6, 14, 57, 17, nanosecond,
zone,
);
let bazi: Bazi = Bazi::from_fixed(fixed);
@@ -566,10 +621,26 @@ mod tests {
let hour: GanZhi = bazi.hour;
println!("fixed: {:?}", fixed);
println!("年: {} ({})", year.alphabet(), year.alphabet_ja());
println!(": {} ({})", month.alphabet(), month.alphabet_ja());
println!("日: {} ({})", day.alphabet(), day.alphabet_ja());
println!("時: {} ({})", hour.alphabet(), hour.alphabet_ja());
println!(
": {} ({})",
year.alphabet(),
year.alphabet_ja()
);
println!(
"月: {} ({})",
month.alphabet(),
month.alphabet_ja()
);
println!(
"日: {} ({})",
day.alphabet(),
day.alphabet_ja()
);
println!(
"時: {} ({})",
hour.alphabet(),
hour.alphabet_ja()
);
assert_eq!(year.alphabet(), "辛丑");
assert_eq!(month.alphabet(), "甲午");
@@ -581,13 +652,13 @@ mod tests {
fn test_bazi_from_utc() {
let nanosecond: u32 = 275_570_000;
let utc: DateTime<Utc> = build_utc(
2021, 7, 6, 5, 54, 34, nanosecond
2021, 7, 6, 5, 54, 34, nanosecond,
);
// Local Time
let nanosecond: u32 = 137_790_000;
let t = NaiveTime::from_hms_nano(
14, 57, 17, nanosecond
14, 57, 17, nanosecond,
);
let bazi: Bazi = Bazi::from_utc(utc, t);
@@ -600,10 +671,26 @@ mod tests {
println!("utc: {:?}", utc);
println!("t: {:?}", t);
println!("年: {} ({})", year.alphabet(), year.alphabet_ja());
println!(": {} ({})", month.alphabet(), month.alphabet_ja());
println!("日: {} ({})", day.alphabet(), day.alphabet_ja());
println!("時: {} ({})", hour.alphabet(), hour.alphabet_ja());
println!(
": {} ({})",
year.alphabet(),
year.alphabet_ja()
);
println!(
"月: {} ({})",
month.alphabet(),
month.alphabet_ja()
);
println!(
"日: {} ({})",
day.alphabet(),
day.alphabet_ja()
);
println!(
"時: {} ({})",
hour.alphabet(),
hour.alphabet_ja()
);
assert_eq!(year.alphabet(), "辛丑");
assert_eq!(month.alphabet(), "甲午");

View File

@@ -4,47 +4,53 @@
//! The box in the middle represents where you are,
//! and 8 boxes which surrounding the middle represent
//! 8 compass directions. For these 9 boxes, plotted
//! special symbols, each of which is called, a "Star" (星).
//! When we say 九星 (Jiu-Xing) in Chinese, "Jiu" means "9",
//! and "Xing" means a "Star". While 九星 (Jiu-Xing)
//! has fixed positions (associated with 洛書 (Lo-Shu)),
//! they change positions over time, and this movement
//! is called 飞泊 (Fei-Po) or "flying" because of how it
//! appears to our eyes when they move.
//! special symbols, each of which is called, a "Star"
//! (星). When we say 九星 (Jiu-Xing) in Chinese, "Jiu"
//! means "9", and "Xing" means a "Star". While 九星
//! (Jiu-Xing) has fixed positions (associated with
//! 洛書 (Lo-Shu)), they change positions over time,
//! and this movement is called 飞泊 (Fei-Po) or
//! "flying" because of how it appears to our eyes when
//! they move.
//!
//! As explained in 八卦 (Ba-Gua) (see: `src/bagua.rs`),
//! there are 2 worldly systems concerned, namely,
//! 先天八卦 (or "the Primordial Heaven") and
//! 後天八卦 (or "the Manifested Heaven"), and we deal
//! with the latter system when we talk about 風水 (Feng-Shui).
//! with the latter system when we talk about 風水
//! (Feng-Shui).
//!
//! In 玄空飞星風水 (Xuan-Kong Fei-Xing Feng-Shui), there is
//! a special name given to the latter system, and is called,
//! 地盤 (Di-Pan). "Di" means "earth", and "Pan" means "board".
//! So, it is basically a board which is drawn at the bottom
//! of any Feng-Shui charts. On 地盤 (Di-Pan), 九星 (Jiu-Xing)
//! are plotted for which the order is fundamentally that of
//! 洛書 (Lo-Shu) order in 八卦 (Ba-Gua). However, they move
//! In 玄空飞星風水 (Xuan-Kong Fei-Xing Feng-Shui),
//! there is a special name given to the latter system,
//! and is called, 地盤 (Di-Pan). "Di" means "earth",
//! and "Pan" means "board". So, it is basically a board
//! which is drawn at the bottom of any Feng-Shui charts.
//! On 地盤 (Di-Pan), 九星 (Jiu-Xing) are plotted for
//! which the order is fundamentally that of 洛書
//! (Lo-Shu) order in 八卦 (Ba-Gua). However, they move
//! (or "fly") over 地盤 (Di-Pan) as time goes.
//! In 玄空飞星風水 (Xuan-Kong Fei-Xing Feng-Shui), there are
//! 3 other boards that are drawn on top of 地盤 (Di-Pan), namely:
//! In 玄空飞星風水 (Xuan-Kong Fei-Xing Feng-Shui),
//! there are 3 other boards that are drawn on top of
//! 地盤 (Di-Pan), namely:
//!
//! - 運盤 (Un-Pan) or 天盤 (Tien-Pan)
//! - 山星 (Shan-Xing)
//! - 向星 (Xiang-Xing)
//!
//! For 運盤 (Un-Pan), positions of 九星 (Jiu-Xing) are determined
//! by construction year for the building in concern which is
//! calculated based on 三元九運 (Sang-Yuan Jiu-Yun),
//! or "9 Yearly Cycles". We could say that 運盤 (Un-Pan)
//! essentially describes the temporal aspect.
//! 山星 (Shan-Xing) and 向星 (Xiang-Xing) are determined
//! by spatial aspects of the building (however, in actual
//! calculations, some temporal aspects comes in).
//! For 運盤 (Un-Pan), positions of 九星 (Jiu-Xing) are
//! determined by construction year for the building in
//! concern which is calculated based on 三元九運
//! (Sang-Yuan Jiu-Yun), or "9 Yearly Cycles". We could
//! say that 運盤 (Un-Pan) essentially describes the
//! temporal aspect. 山星 (Shan-Xing) and 向星
//! (Xiang-Xing) are determined by spatial aspects of
//! the building (however, in actual calculations, some
//! temporal aspects comes in).
//!
//! When these 3 extra boards are placed on top of 地盤 (Di-Pan),
//! the whole thing is called, 下卦図 (Xia-Gua-Tu), or simply
//! referred as 飞星図 (Fei-Xing-Tu), or "The Flying Star Chart".
//! When these 3 extra boards are placed on top of 地盤
//! (Di-Pan), the whole thing is called, 下卦図
//! (Xia-Gua-Tu), or simply referred as 飞星図
//! (Fei-Xing-Tu), or "The Flying Star Chart".
//!
//! Jiu-Xing (九星):
//!
@@ -58,30 +64,24 @@
//! [7] 八白土星 (8 White)
//! [8] 九紫火星 (9 Purple)
use chrono::naive::NaiveDate;
use chrono::Datelike;
use serde::{Deserialize, Serialize};
use sowngwala::time::julian_day_from_generic_date;
use std::collections::HashMap;
use std::convert::TryInto;
use chrono::Datelike;
use chrono::naive::NaiveDate;
use sowngwala::time::julian_day_from_generic_date;
use crate::compass::{
get_opposite_direction,
DIRECTIONS,
get_opposite_direction, DIRECTIONS,
DIRECTION_POSITIONS_IN_CHART,
};
use crate::language::{
Language,
LanguageData,
LanguageTrait,
Language, LanguageData, LanguageTrait,
NameDataTrait,
};
use crate::planet::{Planet, PLANETS};
use crate::utils::{get_json, make_positive};
use crate::wuxing::{WuXing, WU_XING};
use crate::utils::{
get_json,
make_positive,
};
pub const SAN_YUAN_JIU_YUN_START_YEAR: u16 = 1864;
@@ -96,7 +96,8 @@ pub struct JiuXing {
pub planet: Planet,
}
/// A temporary struct for loading JSON data when defining a static const `JIU_XING`.
/// A temporary struct for loading JSON data when
/// defining a static const `JIU_XING`.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct JiuXingRawData {
pub num: u8,
@@ -119,7 +120,9 @@ impl NameDataTrait for JiuXingRawData {
}
}
#[derive(Debug, Clone, Serialize, Deserialize, Copy)]
#[derive(
Debug, Clone, Serialize, Deserialize, Copy,
)]
pub enum XiaGuaTuKind {
UnPanXing, // 運盤
ShanXing, // 山星
@@ -137,7 +140,8 @@ pub struct XiaGuaTu<'a> {
}
lazy_static! {
/// A static vector with 9 items, each represents 九星 (Jiu-Xing).
/// A static vector with 9 items, each represents
/// 九星 (Jiu-Xing).
///
/// [0] 一白水星 (1 White)
/// [1] 二黒土星 (2 Black)
@@ -149,7 +153,8 @@ lazy_static! {
/// [7] 八白土星 (8 White)
/// [8] 九紫火星 (9 Purple)
///
/// For attributes details stored in the vector is found in JSON file:
/// For attributes details stored in the vector is
/// found in JSON file:
/// `src/json/jiuxing.json`
pub static ref JIU_XING: [JiuXing; 9] = {
let json = &include_str!("../json/jiuxing.json");
@@ -184,19 +189,25 @@ lazy_static! {
/// JsValue::from_serde(dir).unwrap()
/// }
/// ```
pub fn get_jiuxing_from_index(index: usize) -> &'static JiuXing {
pub fn get_jiuxing_from_index(
index: usize,
) -> &'static JiuXing {
&JIU_XING[index]
}
lazy_static! {
pub static ref DIRECTION_TO_JIU_XING: HashMap<&'static str, usize> = JIU_XING
pub static ref DIRECTION_TO_JIU_XING: HashMap<&'static str, usize> =
JIU_XING
.iter()
.enumerate()
.map(|(index, jiuxing)| {
let dir = jiuxing.direction.as_str();
match dir {
"" => ("", index),
_ => (jiuxing.direction.as_str(), index),
_ => (
jiuxing.direction.as_str(),
index,
),
}
})
.collect();
@@ -210,17 +221,19 @@ fn jiuxing_index_from_direction(dir: &str) -> usize {
}
lazy_static! {
/// Although 洛書 (Lo-Shu) order is fixed, when 地盤 (Di-Pan)
/// is drawn on a device screen, the mapping for
/// 九星 (Jiu-Xing) changes as the device rotates.
/// For example, 一白水星 (1 White) usually comes to the top
/// of the board when a device is pointing north. However,
/// when pointing north east, 一白水星 (1 White) moves
/// to the top left (which is north west).
/// For 8 compass directions, this constant provides
/// a mapping for the 洛書 (Lo-Shu) order.
/// For "n", 一白水星 (1 White) is the 2nd in the array.
/// For "ne", 一白水星 (1 White) is the 1st in the array.
/// Although 洛書 (Lo-Shu) order is fixed, when
/// 地盤 (Di-Pan) is drawn on a device screen,
/// the mapping for 九星 (Jiu-Xing) changes as
/// the device rotates.
/// For example, 一白水星 (1 White) usually comes
/// to the top of the board when a device is
/// pointing north. However, when pointing north
/// east, 一白水星 (1 White) moves to the top left
/// (which is north west). For 8 compass directions,
/// this constant provides a mapping for the 洛書
/// (Lo-Shu) order. For "n", 一白水星 (1 White) is
/// the 2nd in the array. For "ne", 一白水星
/// (1 White) is the 1st in the array.
///
/// It would look like this:
///
@@ -281,7 +294,9 @@ lazy_static! {
}
/// A getter for `JIU_XING_DI_PAN_POSITIONS`.
pub fn get_jiuxing_dipan_positions_from_direction(direction: &str) -> Option<&[usize; 9]> {
pub fn get_jiuxing_dipan_positions_from_direction(
direction: &str,
) -> Option<&[usize; 9]> {
JIU_XING_DI_PAN_POSITIONS.get(direction)
}
@@ -318,8 +333,10 @@ lazy_static! {
*/
}
/// Given incorrect value for Jiu-Xing index, applies a modulo
/// to normalize it to fit within the range of 0 to 8.
/// Given incorrect value for Jiu-Xing index, applies
/// a modulo to normalize it to fit within the range
/// of 0 to 8.
///
/// Ex.
/// 0 -> 0 ... Stays the same. "0" being 一白水星 (1 White).
/// 8 -> 8 ... Stays the same. "8" being 九紫火星 (9 Purple).
@@ -335,16 +352,18 @@ pub fn normalize_jiuxing(index: i32) -> usize {
}
}
/// Sang-Yuan 三元九運 (Jiu-Yun), or _"9 YEARLY CYCLES"_, is the core
/// concept in 玄空飞星風水 (Xuan-Kong Fei-Xing Feng-Shui),
/// and it tells how 九星 (Jiu-Xing) fly throughout 180 years.
/// Sang-Yuan 三元九運 (Jiu-Yun), or _"9 YEARLY
/// CYCLES"_, is the core concept in 玄空飞星風水
/// (Xuan-Kong Fei-Xing Feng-Shui), and it tells how
/// 九星 (Jiu-Xing) fly throughout 180 years.
/// This function will calculate from the given:
///
/// 1. CURRENT LOCALTIME, and
/// 2. LIU-CHUN (for the year)
///
/// for the corresponding Jiu-Xing, for which the generated board
/// is usually referred as 運盤 (Un-Pan).
/// for the corresponding Jiu-Xing, for which
/// the generated board is usually referred as
/// 運盤 (Un-Pan).
///
/// Example:
/// ```rust
@@ -362,16 +381,21 @@ pub fn normalize_jiuxing(index: i32) -> usize {
/// let index: usize = unpan_xing_index(current, lichun);
/// JsValue::from_f64(index as f64)
/// }
pub fn unpan_xing_index(current: NaiveDate, lichun: NaiveDate) -> usize {
let year: i32 = if (
julian_day_from_generic_date(current)
- julian_day_from_generic_date(lichun)
) < 0_f64 {
pub fn unpan_xing_index(
current: NaiveDate,
lichun: NaiveDate,
) -> usize {
let year: i32 =
if (julian_day_from_generic_date(current)
- julian_day_from_generic_date(lichun))
< 0_f64
{
current.year() - 1
} else {
current.year()
};
let dt: i32 = year - SAN_YUAN_JIU_YUN_START_YEAR as i32;
let dt: i32 =
year - SAN_YUAN_JIU_YUN_START_YEAR as i32;
let norm: i32 = dt % 180;
(norm / 20) as usize
}
@@ -386,15 +410,20 @@ pub fn unpan_xing_index(current: NaiveDate, lichun: NaiveDate) -> usize {
/// the second argument `order` in array) of
/// 九星 (Jiu-Xing) indexes, increments or decrements
/// each in the array, and simply return the array.
/// Depending on whichever currently resides in the center of
/// the board (which is the first argument `center`),
/// the value to increment or decrement changes.
/// For `order` is fundamentally that of the Lo-Shu order
/// (which is defined in `JIU_XING_DI_PAN_POSITIONS`),
/// however, the layout is always different since
/// the position changes depending on which direction
/// the device is pointing as the device rotates.
pub fn fly_flying_stars(center: usize, order: &[usize; 9], reverse: bool) -> [usize; 9] {
/// Depending on whichever currently resides in the
/// center of the board (which is the first argument
/// `center`), the value to increment or decrement
/// changes. For `order` is fundamentally that of the
/// Lo-Shu order (which is defined in
/// `JIU_XING_DI_PAN_POSITIONS`), however, the layout
/// is always different since the position changes
/// depending on which direction the device is
/// pointing as the device rotates.
pub fn fly_flying_stars(
center: usize,
order: &[usize; 9],
reverse: bool,
) -> [usize; 9] {
let diff: usize = center - 4;
order
.iter()
@@ -420,38 +449,48 @@ pub fn fly_flying_stars(center: usize, order: &[usize; 9], reverse: bool) -> [us
// }
/// This is a useful well known formula for finding out
/// whether 山星 (Shan-Xing) or 向星 (Xiang-Xing) is flying
/// in normal order.
/// whether 山星 (Shan-Xing) or 向星 (Xiang-Xing) is
/// flying in normal order.
///
/// IMPORTANT:
/// It does not work when 九星 (Jiu-Xing) is "5". If such the case,
/// center index for Un-Pan must be fed.
fn is_shan_xiang_flying_normal(index: usize, sector: usize) -> bool {
/// It does not work when 九星 (Jiu-Xing) is "5".
/// If such the case, center index for Un-Pan must
/// be fed.
fn is_shan_xiang_flying_normal(
index: usize,
sector: usize,
) -> bool {
let num: usize = index + 1;
let rem = num % 2;
(rem != 0 && sector == 1) || (rem == 0 && sector > 1)
(rem != 0 && sector == 1)
|| (rem == 0 && sector > 1)
}
/// Looking at the 地盤 (Di-Pan) order, finds the current direction facing.
fn direction_from_dipan_order(order: &[usize; 9]) -> &'static str {
/// Looking at the 地盤 (Di-Pan) order, finds the
/// current direction facing.
fn direction_from_dipan_order(
order: &[usize; 9],
) -> &'static str {
JIU_XING_DI_PAN_POSITIONS
.iter()
.find_map(
|(dir, dipan_order)| match order.iter().eq(dipan_order.iter()) {
.find_map(|(dir, dipan_order)| {
match order.iter().eq(dipan_order.iter())
{
true => Some(*dir),
_ => None,
},
)
}
})
.unwrap_or("")
}
/// Calculates for 下卦図 (Xia-Gua-Tu). 1st and 2nd
/// arguments (`unpan_xing_center` and `unpan_xing_order`)
/// are required for all. For calculating a chart
/// for 運盤星 (Un-Pan Xing), that is all we need.
/// However, to calculate charts for 山星 (Shan-Xing)
/// and 向星 (Xiang-Xing), requires 3rd and 4th arguments
/// (`xiang_xing_direction` and `xiang_xing_sector`.
/// arguments (`unpan_xing_center` and
/// `unpan_xing_order`) are required for all.
/// For calculating a chart for 運盤星 (Un-Pan Xing),
/// that is all we need. However, to calculate charts
/// for 山星 (Shan-Xing) and 向星 (Xiang-Xing), requires
/// 3rd and 4th arguments (`xiang_xing_direction` and
/// `xiang_xing_sector`.
///
/// Example:
/// ```rust
@@ -488,9 +527,10 @@ pub fn get_xiaguatu_from_unpan_index<'a>(
) -> HashMap<&'a str, XiaGuaTu<'a>> {
let mut xgtu = HashMap::new();
// `chart` for 運盤星 (Un-Pan Xing) is straight forward.
// The center 九星 (Jiu-Xing) is already given,
// and you simply have to fly the given chart.
// `chart` for 運盤星 (Un-Pan Xing) is straight
// forward. The center 九星 (Jiu-Xing) is already
// given, and you simply have to fly the given
// chart.
xgtu.insert(
"unpan_xing",
XiaGuaTu {
@@ -498,36 +538,32 @@ pub fn get_xiaguatu_from_unpan_index<'a>(
center: Some(unpan_xing_center),
direction: None,
sector: None,
chart: Some(
fly_flying_stars(
chart: Some(fly_flying_stars(
unpan_xing_center,
unpan_xing_order,
false
)
),
false,
)),
},
);
// `chart` for 山星 (Shan-Xing) to be later calculated.
// `direction` for 山星 (Shan-Xing) is just the opposite
// of 向星 (Xiang-Xing).
// `chart` for 山星 (Shan-Xing) to be later
// calculated. `direction` for 山星 (Shan-Xing)
// is just the opposite of 向星 (Xiang-Xing).
xgtu.insert(
"shan_xing",
XiaGuaTu {
kind: XiaGuaTuKind::ShanXing,
center: None,
direction: Some(
get_opposite_direction(
xiang_xing_direction
)
),
direction: Some(get_opposite_direction(
xiang_xing_direction,
)),
sector: Some(xiang_xing_sector),
chart: None,
},
);
// `chart` for 向星 (Xiang-Xing) to be later calculated.
// `direction` is already given.
// `chart` for 向星 (Xiang-Xing) to be later
// calculated. `direction` is already given.
xgtu.insert(
"xiang_xing",
XiaGuaTu {
@@ -541,48 +577,72 @@ pub fn get_xiaguatu_from_unpan_index<'a>(
// First, we need to find out which direction
// the device is currently pointing to.
let curr_dir: &str = direction_from_dipan_order(unpan_xing_order);
let curr_dir: &str =
direction_from_dipan_order(unpan_xing_order);
// Once the direction is found, then we will obtain the compass direction mapping.
let compass_positions: [&str; 9] = DIRECTION_POSITIONS_IN_CHART[curr_dir];
// Once the direction is found, then we will
// obtain the compass direction mapping.
let compass_positions: [&str; 9] =
DIRECTION_POSITIONS_IN_CHART[curr_dir];
// Find `center` and `chart` for both 山星 (Shan-Xing) and 向星 (Xiang-Xing).
// Find `center` and `chart` for both 山星
// (Shan-Xing) and 向星 (Xiang-Xing).
for key in ["shan_xing", "xiang_xing"] {
// Since we only know directions for 山星 (Shan-Xing)
// and 向星 (Xiang-Xing), we will look into the Un-Pan chart,
// and will find out what 九星 (Jiu-Xing) we have for the direction.
// Since we only know directions for 山星
// (Shan-Xing) and 向星 (Xiang-Xing), we will
// look into the Un-Pan chart, and will find
// out what 九星 (Jiu-Xing) we have for the
// direction.
// Initially, we only know the direction.
let dir: &str = xgtu.get(key).unwrap().direction.unwrap();
let dir: &str =
xgtu.get(key).unwrap().direction.unwrap();
// For the direction, find out its array index.
let pos: usize = compass_positions.iter().position(|&d| d == dir).unwrap();
let pos: usize = compass_positions
.iter()
.position(|&d| d == dir)
.unwrap();
// Once the index is found, then find out its 九星 (Jiu-Xing).
let center: usize = (xgtu.get("unpan_xing").unwrap().chart.unwrap())[pos];
// Once the index is found, then find out its
// 九星 (Jiu-Xing).
let center: usize = (xgtu
.get("unpan_xing")
.unwrap()
.chart
.unwrap())[pos];
let prev: &XiaGuaTu = xgtu.get(key).unwrap();
// It is important to figure out whether it is flying
// in normal or reverse order. To do so, we will
// use a useful well known formula.
let normal: bool = is_shan_xiang_flying_normal(
// Having 五黄土星 (5 Yellow) is a special case,
// and the formula does not work. Therefore,
// replacing it with 運盤星 (Un-Pan Xing) index.
// It is important to figure out whether it
// is flying in normal or reverse order.
// To do so, we will use a useful well known
// formula.
let normal: bool =
is_shan_xiang_flying_normal(
// Having 五黄土星 (5 Yellow) is a
// special case, and the formula does
// not work. Therefore, replacing it
// with 運盤星 (Un-Pan Xing) index.
if center == 4 {
xgtu.get("unpan_xing").unwrap().center.unwrap()
xgtu.get("unpan_xing")
.unwrap()
.center
.unwrap()
} else {
center
},
xgtu.get(key).unwrap().sector.unwrap(),
xgtu.get(key)
.unwrap()
.sector
.unwrap(),
);
// Now, calculate for the flying chart.
let chart: [usize; 9] = fly_flying_stars(
center,
unpan_xing_order,
normal
normal,
);
*xgtu.get_mut(key).unwrap() = XiaGuaTu {
@@ -611,14 +671,18 @@ mod tests {
#[test]
fn test_constant_direction_to_jiuxing() {
assert_eq!(*DIRECTION_TO_JIU_XING.get("n").unwrap(), 0);
assert_eq!(
*DIRECTION_TO_JIU_XING.get("n").unwrap(),
0
);
}
// TODO: jiuxing_index_from_direction
// TODO: JIU_XING_DI_PAN_POSITIONS
#[test]
fn test_get_jiuxing_dipan_positions_from_direction() {
fn test_get_jiuxing_dipan_positions_from_direction(
) {
let exp = [5, 0, 7, 6, 4, 2, 1, 8, 3];
assert_eq!(
get_jiuxing_dipan_positions_from_direction("n").unwrap(),
@@ -635,12 +699,16 @@ mod tests {
#[test]
fn normalize_jiuxing_all() {
let arr: [usize; 11] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let exp: [usize; 11] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 1];
let arr: [usize; 11] =
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let exp: [usize; 11] =
[0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 1];
let res: [usize; 11] = arr
.iter()
.map(|index: &usize| normalize_jiuxing(*index as i32))
.map(|index: &usize| {
normalize_jiuxing(*index as i32)
})
.collect::<Vec<usize>>()
.try_into()
.unwrap();
@@ -654,89 +722,146 @@ mod tests {
// TODO: is_shan_xiang_flying_normal
// TODO: get_xiaguatu_from_unpan_index
// ===================================================================
// ===============================================
// LO-SHU ORDER - Normal Order
// ===================================================================
// ===============================================
// Fly *NORMAL* for Lo-Shu Order: [4] 五黄土星 (5 Green)
/// Fly *NORMAL* for Lo-Shu Order:
/// [4] 五黄土星 (5 Green)
#[test]
fn fly_stars_normal_lo_shu_5_green() {
let center: usize = 4; // [4] 五黄土星 (5 Green)
let order: &[usize; 9] = JIU_XING_DI_PAN_POSITIONS.get("n").unwrap();
let exp: [usize; 9] = [5, 0, 7, 6, 4, 2, 1, 8, 3];
let order: &[usize; 9] =
JIU_XING_DI_PAN_POSITIONS
.get("n")
.unwrap();
let exp: [usize; 9] =
[5, 0, 7, 6, 4, 2, 1, 8, 3];
assert_eq!(fly_flying_stars(center, order, false), exp);
assert_eq!(
fly_flying_stars(center, order, false),
exp
);
}
// Fly *NORMAL* for Lo-Shu Order: [5] 六白金星 (6 White)
/// Fly *NORMAL* for Lo-Shu Order:
/// [5] 六白金星 (6 White)
#[test]
fn fly_stars_normal_lo_shu_6_white() {
let center: usize = 5; // [5] 六白金星 (6 White)
let order: &[usize; 9] = JIU_XING_DI_PAN_POSITIONS.get("n").unwrap();
let exp: [usize; 9] = [6, 1, 8, 7, 5, 3, 2, 0, 4];
let order: &[usize; 9] =
JIU_XING_DI_PAN_POSITIONS
.get("n")
.unwrap();
let exp: [usize; 9] =
[6, 1, 8, 7, 5, 3, 2, 0, 4];
assert_eq!(fly_flying_stars(center, order, false), exp);
assert_eq!(
fly_flying_stars(center, order, false),
exp
);
}
// Fly *NORMAL* for Lo-Shu Order: [6] 七赤金星 (7 Red)
/// Fly *NORMAL* for Lo-Shu Order:
/// [6] 七赤金星 (7 Red)
#[test]
fn fly_stars_normal_lo_shu_7_red() {
let center: usize = 6; // [6] 七赤金星 (7 Red)
let order: &[usize; 9] = JIU_XING_DI_PAN_POSITIONS.get("n").unwrap();
let exp: [usize; 9] = [7, 2, 0, 8, 6, 4, 3, 1, 5];
let order: &[usize; 9] =
JIU_XING_DI_PAN_POSITIONS
.get("n")
.unwrap();
let exp: [usize; 9] =
[7, 2, 0, 8, 6, 4, 3, 1, 5];
assert_eq!(fly_flying_stars(center, order, false), exp);
assert_eq!(
fly_flying_stars(center, order, false),
exp
);
}
// Fly *NORMAL* for Lo-Shu Order: [7] 八白土星 (8 White)
/// Fly *NORMAL* for Lo-Shu Order:
/// [7] 八白土星 (8 White)
#[test]
fn fly_stars_normal_lo_shu_8_white() {
let center: usize = 7; // [7] 八白土星 (8 White)
let order: &[usize; 9] = JIU_XING_DI_PAN_POSITIONS.get("n").unwrap();
let exp: [usize; 9] = [8, 3, 1, 0, 7, 5, 4, 2, 6];
let order: &[usize; 9] =
JIU_XING_DI_PAN_POSITIONS
.get("n")
.unwrap();
let exp: [usize; 9] =
[8, 3, 1, 0, 7, 5, 4, 2, 6];
assert_eq!(fly_flying_stars(center, order, false), exp);
assert_eq!(
fly_flying_stars(center, order, false),
exp
);
}
// Fly *NORMAL* for Lo-Shu Order: [8] 九紫火星 (9 Purple)
/// Fly *NORMAL* for Lo-Shu Order:
/// [8] 九紫火星 (9 Purple)
#[test]
fn fly_stars_normal_lo_shu_9_purple() {
let center: usize = 8; // [8] 九紫火星 (9 Purple)
let order: &[usize; 9] = JIU_XING_DI_PAN_POSITIONS.get("n").unwrap();
let exp: [usize; 9] = [0, 4, 2, 1, 8, 6, 5, 3, 7];
let order: &[usize; 9] =
JIU_XING_DI_PAN_POSITIONS
.get("n")
.unwrap();
let exp: [usize; 9] =
[0, 4, 2, 1, 8, 6, 5, 3, 7];
assert_eq!(fly_flying_stars(center, order, false), exp);
assert_eq!(
fly_flying_stars(center, order, false),
exp
);
}
// ===================================================================
// ===============================================
// LO-SHU ORDER - Reverse Order
// ===================================================================
// ===============================================
// Fly *REVERSE* for Lo-Shu Order (North): [4] 五黄土星 (5 Green)
/// Fly *REVERSE* for Lo-Shu Order (North):
/// [4] 五黄土星 (5 Green)
#[test]
fn fly_stars_reverse_5_green_north() {
let center: usize = 4; // [4] 五黄土星 (5 Green)
let order: &[usize; 9] = JIU_XING_DI_PAN_POSITIONS.get("n").unwrap();
let exp: [usize; 9] = [3, 8, 1, 2, 4, 6, 7, 0, 5];
let order: &[usize; 9] =
JIU_XING_DI_PAN_POSITIONS
.get("n")
.unwrap();
let exp: [usize; 9] =
[3, 8, 1, 2, 4, 6, 7, 0, 5];
assert_eq!(fly_flying_stars(center, order,true), exp);
assert_eq!(
fly_flying_stars(center, order, true),
exp
);
}
// Fly *REVERSE* for Lo-Shu Order (North-East): [4] 五黄土星 (5 Green)
/// Fly *REVERSE* for Lo-Shu Order (North-East):
/// [4] 五黄土星 (5 Green)
#[test]
fn fly_stars_reverse_lo_shu_5_green_north_east() {
let center: usize = 4; // [4] 五黄土星 (5 Green)
let order: &[usize; 9] = JIU_XING_DI_PAN_POSITIONS.get("ne").unwrap();
let exp: [usize; 9] = [8, 1, 6, 3, 4, 5, 2, 7, 0];
let order: &[usize; 9] =
JIU_XING_DI_PAN_POSITIONS
.get("ne")
.unwrap();
let exp: [usize; 9] =
[8, 1, 6, 3, 4, 5, 2, 7, 0];
assert_eq!(fly_flying_stars(center, order, true), exp);
assert_eq!(
fly_flying_stars(center, order, true),
exp
);
}
// ===================================================================
// ===============================================
// COMPASS CLOCKWISE - Normal Order
// ===================================================================
// ===============================================
// Fly *NORMAL* for COMPASS CLOCKWISE: [4] 五黄土星 (5 Yellow)
// Fly *NORMAL* for COMPASS CLOCKWISE:
// [4] 五黄土星 (5 Yellow)
// #[test]
// fn fly_stars_normal_lo_shu_5_yellow() {
// let center: usize = 4; // [4] 五黄土星 (5 Yellow)

View File

@@ -25,7 +25,10 @@ pub struct LanguageData {
}
impl LanguageDetails {
pub fn new(alphabet: &str, phonetic: &str) -> Self {
pub fn new(
alphabet: &str,
phonetic: &str,
) -> Self {
LanguageDetails {
alphabet: alphabet.to_string(),
phonetic: phonetic.to_string(),
@@ -55,11 +58,16 @@ pub trait LanguageTrait {
pub trait NameDataTrait {
fn name(&self) -> Box<LanguageData>;
fn language_details(details: &[String]) -> LanguageDetails {
fn language_details(
details: &[String],
) -> LanguageDetails {
if details.is_empty() {
LanguageDetails::new("", "")
} else {
LanguageDetails::new(&details[0], &details[1])
LanguageDetails::new(
&details[0],
&details[1],
)
}
}
@@ -69,8 +77,12 @@ pub trait NameDataTrait {
en: self.name().en,
ja: Self::language_details(&name.ja),
vi: Self::language_details(&name.vi),
zh_cn: Self::language_details(&name.zh_cn),
zh_tw: Self::language_details(&name.zh_tw),
zh_cn: Self::language_details(
&name.zh_cn,
),
zh_tw: Self::language_details(
&name.zh_tw,
),
}
}
}

View File

@@ -1,39 +1,42 @@
//! Information about planets in our solar system.
//! Notice the planets in `PLANETS` are stored in a special order
//! known as _the Ptolemaic Order_. In many ancient traditions,
//! when a man is deceased, he will depart the Earth,
//! and head toward the Moon. Leaving the Moon behind,
//! the Mercury, the Venus, and the Sun. He will continue
//! his journey after the Sun, this time, to _the outer planets_,
//! Notice the planets in `PLANETS` are stored in
//! a special order known as _the Ptolemaic Order_.
//! In many ancient traditions, when a man is deceased,
//! he will depart the Earth, and head toward the Moon.
//! Leaving the Moon behind, the Mercury, the Venus,
//! and the Sun. He will continue his journey after
//! the Sun, this time, to _the outer planets_,
//! that are the Mars, the Jupiter, and the Saturn.
//!
//! After all, this library provides methodologies
//! _NOT_ for _"astronomy"_, but for _"astrology"_, hence,
//! follows the tradition which was common to the ancients.
//! _NOT_ for _"astronomy"_, but for _"astrology"_,
//! hence, follows the tradition which was common to
//! the ancients.
//!
//! Also noteworthy that, according to Rudolf Steiner,
//! "Mercury" was formerly known as "Venus" in ancient times.
//! Yet, it is only so when we are talking about the order
//! of the _physical_ planets, not in its _symbolical_ sense.
//! For instance, when ancients mentioned of "Mercury",
//! it was simply about "Mercury" and not "Venus".
//! "Mercury" was formerly known as "Venus" in ancient
//! times. Yet, it is only so when we are talking about
//! the order of the _physical_ planets, not in its
//! _symbolical_ sense. For instance, when ancients
//! mentioned of "Mercury", it was simply about
//! "Mercury" and not "Venus".
use serde::{Deserialize, Serialize};
use crate::language::{
Language,
LanguageData,
LanguageTrait,
Language, LanguageData, LanguageTrait,
NameDataTrait,
};
use crate::utils::get_json;
/// A struct representing a planet and stores its attributes.
/// A struct representing a planet and stores its
/// attributes.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Planet {
pub name: Language,
}
/// A temporary struct for loading JSON data when defining a static const `PLANETS`.
/// A temporary struct for loading JSON data when
/// defining a static const `PLANETS`.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PlanetRawData {
pub name: LanguageData,
@@ -52,8 +55,9 @@ impl NameDataTrait for PlanetRawData {
}
lazy_static! {
/// A static vector with 11 items, each represents a planet
/// in our solar system. Planets are in Ptolemaic order.
/// A static vector with 11 items, each represents
/// a planet in our solar system. Planets are in
/// Ptolemaic order.
///
/// [0] Earth
/// [1] Moon
@@ -67,7 +71,8 @@ lazy_static! {
/// [9] Neptune
/// [10] Pluto
///
/// For attributes details stored in the vector is found in JSON file:
/// For attributes details stored in the vector is
/// found in JSON file:
/// `src/json/planets.json`
pub static ref PLANETS: Vec<Planet> = {
let json = &include_str!("../json/planet.json");

View File

@@ -1,34 +1,40 @@
//! 生死衰旺 (Sheng-Si Shuai-Wang) is just a combination
//! of 4 Chinese characters, each being:
//! 生死衰旺 (Sheng-Si Shuai-Wang) is just a
//! combination of 4 Chinese characters, each being:
//!
//! (1) Growing --> 生 (Sheng)
//! (2) Deadly --> 死 (Si)
//! (3) Perishing --> 衰 (Shuai)
//! (4) Prosperous --> 旺 (Wang)
//!
//! They are often used in 四柱命理学 (The Four Pillars of Destiny),
//! but used in Feng-Shui as well. It simply suggests
//! that there are 4 states to the energy occupying the space.
//! In 玄空飞星風水 (Xuan-Kong Fei-Xing Feng-Shui),
//! it describes the state for the target year
//! in 三元九運 (Sang-Yuan Jiu-Yun),
//! especially, for its 向星 (Xiang-Xing).
//! They are often used in 四柱命理学 (The Four Pillars
//! of Destiny), but used in Feng-Shui as well.
//! It simply suggests that there are 4 states to
//! the energy occupying the space. In 玄空飞星風水
//! (Xuan-Kong Fei-Xing Feng-Shui), it describes
//! the state for the target year in 三元九運
//! (Sang-Yuan Jiu-Yun), especially, for its 向星
//! (Xiang-Xing).
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use crate::jiuxing::normalize_jiuxing;
/// A struct representing 生死衰旺 (Sheng-Si Shuai-Wang).
/// `key` would be: "sheng", "si", "shuai", or "wang".
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
/// A struct representing 生死衰旺 (Sheng-Si
/// Shuai-Wang). `key` would be: "sheng", "si",
/// "shuai", or "wang".
#[derive(
Debug, Clone, Deserialize, Serialize, PartialEq,
)]
pub struct ShengSi<'a> {
pub key: &'a str,
pub kanji: &'a str,
pub meaning: &'a str,
}
/// A struct holding allocations of 生死衰旺 (Sheng-Si Shuai-Wang) for the given year.
/// For `usize` (in `Vec<usize>`) is 九星 (Jiu-Xing) index.
/// A struct holding allocations of 生死衰旺
/// (Sheng-Si Shuai-Wang) for the given year.
/// For `usize` (in `Vec<usize>`) is 九星
/// (Jiu-Xing) index.
#[derive(Debug, Clone)]
pub struct ShengSiYearlyAlloc {
pub wang: Vec<usize>,
@@ -38,7 +44,10 @@ pub struct ShengSiYearlyAlloc {
}
impl ShengSiYearlyAlloc {
pub fn accessor(&self, name: &str) -> Option<&Vec<usize>> {
pub fn accessor(
&self,
name: &str,
) -> Option<&Vec<usize>> {
match name {
"wang" => Some(&self.wang),
"sheng" => Some(&self.sheng),
@@ -50,8 +59,8 @@ impl ShengSiYearlyAlloc {
}
lazy_static! {
/// A HashMap for 生死衰旺 (Sheng-Si Shuai-Wang) by key
/// (for each holds `ShengSi`).
/// A HashMap for 生死衰旺 (Sheng-Si Shuai-Wang)
/// by key (for each holds `ShengSi`).
pub static ref SHENG_SI: HashMap<&'static str, ShengSi<'static>> = HashMap::from([
("sheng", ShengSi { key: "sheng", kanji: "", meaning: "growth" }),
("si", ShengSi { key: "si", kanji: "", meaning: "death" }),
@@ -59,18 +68,23 @@ lazy_static! {
("wang", ShengSi { key: "wang", kanji: "", meaning: "prosperous" }),
]);
/// For every year, some 九星 (Jiu-Xing) maybe in 旺 (Wang = Prospering)
/// phase, but some maybe in 死 (Si = Dying). 生死衰旺 (Sheng-Si Shuai-Wang)
/// for 九星 (Jiu-Xing) is no random, but has certain patterns,
/// and is repeated every 9 years. This cycle is called
/// 三元九運 (Sang-Yuan Jiu-Yun), and given the 運盤星 (Un-Pan Xing) index
/// for the specific year, you can tell of 生死衰旺 (Sheng-Si Shuai-Wang)
/// for all the other 九星 (Jiu-Xing). Here, it is constructing
/// the patterns for 9 years, and making them into a static vector
/// for which each index being the 運盤星 (Un-Pan Xing) index.
/// If you know the 運盤星 (Un-Pan Xing) index for the year,
/// this static vector will tell you 生死衰旺 (Sheng-Si Shuai-Wang)
/// for all 九星 (Jiu-Xing).
/// For every year, some 九星 (Jiu-Xing) maybe in
/// 旺 (Wang = Prospering) phase, but some maybe
/// in 死 (Si = Dying). 生死衰旺 (Sheng-Si
/// Shuai-Wang) for 九星 (Jiu-Xing) is no random,
/// but has certain patterns, and is repeated every
/// 9 years. This cycle is called 三元九運
/// (Sang-Yuan Jiu-Yun), and given the 運盤星
/// (Un-Pan Xing) index for the specific year, you
/// can tell of 生死衰旺 (Sheng-Si Shuai-Wang) for
/// all the other 九星 (Jiu-Xing). Here, it is
/// constructing the patterns for 9 years, and
/// making them into a static vector for which each
/// index being the 運盤星 (Un-Pan Xing) index.
/// If you know the 運盤星 (Un-Pan Xing) index for
/// the year, this static vector will tell you
/// 生死衰旺 (Sheng-Si Shuai-Wang) for all 九星
/// (Jiu-Xing).
pub static ref SHENG_SI_ALLOC: Vec<ShengSiYearlyAlloc> = (0..9)
.map(|i: i32| {
// 旺 (Wang)
@@ -80,7 +94,7 @@ lazy_static! {
let sheng: Vec<usize> = [1, 2]
.iter()
.map(|num| {
normalize_jiuxing((unpan_id + num) as i32)
normalize_jiuxing(unpan_id + num)
})
.collect::<Vec<usize>>();
@@ -88,7 +102,7 @@ lazy_static! {
let shuai: Vec<usize> = [1, 2]
.iter()
.map(|num| {
normalize_jiuxing((unpan_id - num) as i32)
normalize_jiuxing(unpan_id - num)
})
.collect::<Vec<usize>>();
@@ -101,25 +115,29 @@ lazy_static! {
.collect::<Vec<usize>>();
ShengSiYearlyAlloc {
// 運盤星 (Un-Pan Xing) is always the 旺 (wang) for the year.
// 運盤星 (Un-Pan Xing) is always the
// 旺 (wang) for the year.
wang: vec!(unpan_id as usize),
// Two 九星 (Jiu-Xing) that *proceed* 運盤星 (Un-Pan Xing)
// is always the 生 (Sheng).
// Two 九星 (Jiu-Xing) that *proceed*
// 運盤星 (Un-Pan Xing) is always the
// 生 (Sheng).
sheng,
// Two 九星 (Jiu-Xing) that *preceed* 運盤星 (Un-Pan Xing)
// is always the 衰 (Shuai). However, there is
// an exceptional case when 一白水星 (1 White) were
// given for the 運盤星 (Un-Pan Xing) because
// it should be converted to 九紫火星 (9 Purple).
// Two 九星 (Jiu-Xing) that *preceed*
// 運盤星 (Un-Pan Xing) is always the
// 衰 (Shuai). However, there is
// an exceptional case when 一白水星
// (1 White) were given for the 運盤星
// (Un-Pan Xing) because it should be
// converted to 九紫火星 (9 Purple).
shuai: if unpan_id == 0 {
vec!(8)
} else {
shuai
},
// Calculation for 死 (Si) is a bit tricky...
// Calculation for 死 (Si) is tricky...
si: si
.iter()
.filter_map(|&index| {
@@ -139,9 +157,10 @@ lazy_static! {
.collect();
}
/// Given 運盤 (Un-Pan) index and a layout for the current
/// 運盤 (Un-Pan) positions (`&[usize; 9]`), returns the corresponding
/// 生死衰旺 (Sheng-Si Shuai-Wang) situation.
/// Given 運盤 (Un-Pan) index and a layout for the
/// current 運盤 (Un-Pan) positions (`&[usize; 9]`),
/// returns the corresponding 生死衰旺 (Sheng-Si
/// Shuai-Wang) situation.
///
/// Example:
/// ```rust
@@ -168,39 +187,45 @@ pub fn get_shengsi_mapping(
unpan_id: usize,
unpan_xing_chart: &[usize; 9],
) -> Vec<Option<&ShengSi>> {
// At first, we will get 生死衰旺 (Sheng-Si Shuai-Wang)
// for the given 運盤星 (Un-Pan Xing).
let yearly_allocs: &ShengSiYearlyAlloc = &SHENG_SI_ALLOC[unpan_id];
// At first, we will get 生死衰旺 (Sheng-Si
// Shuai-Wang) for the given 運盤星 (Un-Pan
// Xing).
let yearly_allocs: &ShengSiYearlyAlloc =
&SHENG_SI_ALLOC[unpan_id];
// Now, 生死衰旺 (Sheng-Si Shuai-Wang) just obtained
// is mapped by "sheng", "si", "shuai", and "wang".
// However, we rather want to look up by 九星 (Jiu-Xing) index.
// So, we are creating a temporary mapping here.
// Though, in the next line, we are just initializing
// each in the mapping with `None`.
let mut lookup: HashMap<usize, Option<&ShengSi>> = (0..9)
// However, we rather want to look up by 九星
// (Jiu-Xing) index. So, we are creating a temporary
// mapping here. Though, in the next line, we are
// just initializing each in the mapping with `None`.
let mut lookup: HashMap<usize, Option<&ShengSi>> =
(0..9)
.map(|index: usize| (index, None))
.into_iter()
.collect();
// Once the mapping being initialized, we are
// creating the mapping.
for key in ["sheng", "si", "shuai", "wang"] {
let data: Option<&ShengSi> = SHENG_SI.get(key);
let data: Option<&ShengSi> =
SHENG_SI.get(key);
for index in yearly_allocs.accessor(key).unwrap() {
for index in
yearly_allocs.accessor(key).unwrap()
{
*lookup.get_mut(index).unwrap() = data;
}
}
// We have 運盤 (Un-Pan) chart given. All we want is
// to find 生死衰旺 (Sheng-Si Shuai-Wang)
// for each 九星 (Jiu-Xing) in the 運盤 (Un-Pan) chart
// (using the temporary mapping just created).
// We have 運盤 (Un-Pan) chart given. All we want
// is to find 生死衰旺 (Sheng-Si Shuai-Wang) for
// each 九星 (Jiu-Xing) in the 運盤 (Un-Pan)
// chart (using the temporary mapping just created).
unpan_xing_chart
.iter()
.map(|index: &usize| *lookup.get(index).unwrap())
.into_iter()
.map(|index: &usize| {
*lookup.get(index).unwrap()
})
.collect()
}
@@ -210,7 +235,10 @@ mod tests {
#[test]
fn test_constant_sheng_si() {
assert_eq!(SHENG_SI.get("sheng").unwrap().key, "sheng");
assert_eq!(
SHENG_SI.get("sheng").unwrap().key,
"sheng"
);
}
#[test]
@@ -226,7 +254,10 @@ mod tests {
#[test]
fn test_get_shengsi_mapping() {
let res = get_shengsi_mapping(6, &[2, 0, 4, 7, 6, 5, 8, 3, 1]);
let res = get_shengsi_mapping(
6,
&[2, 0, 4, 7, 6, 5, 8, 3, 1],
);
assert_eq!(res[0].unwrap().key, "si"); // 2
assert_eq!(res[1], None); // 0
assert_eq!(res[2].unwrap().key, "shuai"); // 4

View File

@@ -1,20 +1,17 @@
//! A module for 二十四节气 (Er-Shi-Si Jie-Qi).
//! Or, for calculating 立春 (Li-Chun).
use chrono::Datelike;
use chrono::naive::NaiveDate;
use chrono::Datelike;
use serde::{Deserialize, Serialize};
use sowngwala::time::add_date;
use crate::language::{
Language,
LanguageData,
LanguageTrait,
Language, LanguageData, LanguageTrait,
NameDataTrait,
};
use crate::utils::{
get_json,
longitude_of_the_sun_from_generic_date,
get_json, longitude_of_the_sun_from_generic_date,
};
#[derive(Debug)]
@@ -45,8 +42,10 @@ impl NameDataTrait for SolarTermRawData {
lazy_static! {
pub static ref SOLAR_TERMS: Vec<SolarTerm> = {
let json = &include_str!("../json/solar_terms.json");
let data: Vec<SolarTermRawData> = get_json::<SolarTermRawData>(json);
let json =
&include_str!("../json/solar_terms.json");
let data: Vec<SolarTermRawData> =
get_json::<SolarTermRawData>(json);
data.iter()
.map(|item| {
let item = item.clone();
@@ -61,8 +60,11 @@ lazy_static! {
}
#[allow(clippy::many_single_char_names)]
pub fn get_last_term(date: NaiveDate) -> (f64, NaiveDate) {
let lng_0: f64 = longitude_of_the_sun_from_generic_date(date);
pub fn get_last_term(
date: NaiveDate,
) -> (f64, NaiveDate) {
let lng_0: f64 =
longitude_of_the_sun_from_generic_date(date);
// For the unit of 15, we want the last term.
// Ex.
// 317.435511 --> 315.0
@@ -79,7 +81,10 @@ pub fn get_last_term(date: NaiveDate) -> (f64, NaiveDate) {
// Go back by one day a time.
while term.is_none() {
let lng: f64 = longitude_of_the_sun_from_generic_date(next);
let lng: f64 =
longitude_of_the_sun_from_generic_date(
next,
);
// See if the target falls in the current date.
if lng <= target && lng > (target - 1.0) {
term = prev;
@@ -121,9 +126,10 @@ mod tests {
#[test]
fn test_get_last_term() {
let (_lng, term): (f64, NaiveDate) = get_last_term(
NaiveDate::from_ymd(2022, 2, 6)
);
let (_lng, term): (f64, NaiveDate) =
get_last_term(NaiveDate::from_ymd(
2022, 2, 6,
));
assert_eq!(term.year(), 2022);
assert_eq!(term.month(), 2);
assert_eq!(term.day(), 4);

View File

@@ -1,14 +1,13 @@
/**
* Modules used ONLY from tests.
*/
use chrono::naive::{
NaiveDate,
NaiveDateTime,
};
use chrono::naive::{NaiveDate, NaiveDateTime};
use serde::{Deserialize, Serialize};
use std::convert::From;
#[derive(Serialize, Deserialize, Debug, Copy, Clone)]
#[derive(
Serialize, Deserialize, Debug, Copy, Clone,
)]
pub struct DateParams {
pub year: i32,
pub month: u32,
@@ -25,7 +24,9 @@ impl From<DateParams> for NaiveDate {
}
}
#[derive(Serialize, Deserialize, Debug, Copy, Clone)]
#[derive(
Serialize, Deserialize, Debug, Copy, Clone,
)]
pub struct DateTimeParams {
pub year: i32,
pub month: u32,
@@ -34,7 +35,7 @@ pub struct DateTimeParams {
pub minute: u32,
pub second: u32,
pub nanosecond: u32,
pub zone: i32
pub zone: i32,
}
impl From<DateTimeParams> for NaiveDateTime {
@@ -43,7 +44,8 @@ impl From<DateTimeParams> for NaiveDateTime {
params.year,
params.month,
params.day,
).and_hms(
)
.and_hms(
params.hour,
params.minute,
params.second,

View File

@@ -6,7 +6,9 @@ use serde::Deserialize;
use sowngwala::sun::ecliptic_position_of_the_sun_from_generic_date;
pub fn get_json<'a, T: Deserialize<'a>>(json: &'a str) -> Vec<T> {
pub fn get_json<'a, T: Deserialize<'a>>(
json: &'a str,
) -> Vec<T> {
match serde_json::from_str(json) {
Ok(json) => json,
Err(err) => panic!("Error: {}", err),
@@ -14,24 +16,33 @@ pub fn get_json<'a, T: Deserialize<'a>>(json: &'a str) -> Vec<T> {
}
/// For the given Vec, sorts by given order.
pub fn make_sort<T: Clone>(order: Vec<u8>) -> Box<dyn Fn(Vec<T>) -> Vec<T>> {
pub fn make_sort<T: Clone>(
order: Vec<u8>,
) -> Box<dyn Fn(Vec<T>) -> Vec<T>> {
Box::new(move |source: Vec<T>| -> Vec<T> {
order
.clone()
.into_iter()
.map(|index| source[index as usize].clone())
.map(|index| {
source[index as usize].clone()
})
.collect()
})
}
/// Increments by the given step until it becomes more than 0.
pub fn make_positive(step: u32) -> Box<dyn Fn(i32) -> u32> {
pub fn make_positive(
step: u32,
) -> Box<dyn Fn(i32) -> u32> {
Box::new(move |mut num: i32| -> u32 {
let limit = 10000;
let mut cnt = 0;
while num < 0 {
if cnt > limit {
panic!("Iteration reached: {}", limit);
panic!(
"Iteration reached: {}",
limit
);
}
num += step as i32;
cnt += 1;
@@ -40,11 +51,17 @@ pub fn make_positive(step: u32) -> Box<dyn Fn(i32) -> u32> {
})
}
pub fn longitude_of_the_sun_from_generic_date<T>(date: T) -> f64
where T: Datelike,
pub fn longitude_of_the_sun_from_generic_date<T>(
date: T,
) -> f64
where
T: Datelike,
T: std::marker::Copy,
T: std::fmt::Debug,
T: std::fmt::Display
T: std::fmt::Display,
{
ecliptic_position_of_the_sun_from_generic_date(date).lng
ecliptic_position_of_the_sun_from_generic_date(
date,
)
.lng
}

View File

@@ -2,9 +2,7 @@
use serde::{Deserialize, Serialize};
use crate::language::{
Language,
LanguageData,
LanguageTrait,
Language, LanguageData, LanguageTrait,
NameDataTrait,
};
use crate::utils::get_json;
@@ -15,7 +13,8 @@ pub struct WuXing {
pub name: Language,
}
/// A temporary struct for loading JSON data when defining a static const `WU_XING`.
/// A temporary struct for loading JSON data when
/// defining a static const `WU_XING`.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WuXingRawData {
pub name: LanguageData,
@@ -34,9 +33,11 @@ impl NameDataTrait for WuXingRawData {
}
lazy_static! {
/// A static vector with 5 items, each represents 五行 (Wu-Xing).
/// A static vector with 5 items, each represents
/// 五行 (Wu-Xing).
///
/// For attributes details stored in the vector is found in JSON file:
/// For attributes details stored in the vector is
/// found in JSON file:
/// `src/json/wuxing.json`
pub static ref WU_XING: Vec<WuXing> = {
let json = &include_str!("../json/wuxing.json");