Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PoC: generate static refs from ../_data folder #50

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions rust/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
target
src/_data
src/_data.rs
30 changes: 30 additions & 0 deletions rust/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions rust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,10 @@ build = "gen_data.rs"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
lazy_static = "1.4.0"
serde = { version = "1.0.194", features = ["derive"] }
serde_json = "1.0.110"

[build-dependencies]
serde = { version = "1.0.194", features = ["derive"] }
serde_json = { version = "1.0.110", features = ["preserve_order"] }
163 changes: 158 additions & 5 deletions rust/gen_data.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,172 @@
use serde::{Deserialize, Serialize};
use std::{fs, io, path::Path};

fn copy_dir_all(src: impl AsRef<Path>, dst: impl AsRef<Path>) -> io::Result<()> {
fs::create_dir_all(&dst)?;
#[derive(Debug, Serialize, Deserialize)]
pub struct Name {
pub ar: String,
pub en: String,
pub fr: String,
}

#[derive(Debug, Serialize, Deserialize, PartialEq)]
pub enum Type {
#[serde(rename = "UNIVERSITY")]
University,
#[serde(rename = "ACADEMY")]
Academy,
#[serde(rename = "PRIVATE_SCHOOL")]
PrivateSchool,
#[serde(rename = "INSTITUTE")]
Institute,
#[serde(rename = "FACULTY")]
Faculty,
#[serde(rename = "DEPARTMENT")]
Department,
#[serde(rename = "SPECIALTY")]
Specialty,
#[serde(rename = "SECTOR")]
Sector,
}

impl ToString for Type {
fn to_string(&self) -> String {
match self {
Type::University => format!("Type::University"),
Type::Academy => format!("Type::Academy"),
Type::PrivateSchool => format!("Type::PrivateSchool"),
Type::Institute => format!("Type::Institute"),
Type::Faculty => format!("Type::Faculty"),
Type::Department => format!("Type::Department"),
Type::Specialty => format!("Type::Specialty"),
Type::Sector => format!("Type::Sector"),
}
}
}

#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
pub struct Terms {
#[serde(rename = "perYear")]
pub per_year: usize,
pub slots: Vec<usize>,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct Schema {
pub name: Name,
#[serde(rename = "type")]
pub ty: Type,
pub terms: Option<Terms>,
}

fn gen_static_refs(
src: impl AsRef<Path>,
dst: impl AsRef<Path>,
gen_statics: &mut Vec<String>,
count: &mut usize,
) -> io::Result<()> {
for entry in fs::read_dir(src)? {
let entry = entry?;
let ty = entry.file_type()?;
if ty.is_dir() {
copy_dir_all(entry.path(), dst.as_ref().join(entry.file_name()))?;
gen_static_refs(
entry.path(),
dst.as_ref().join(entry.file_name()),
gen_statics,
count,
)?;
} else {
fs::copy(entry.path(), dst.as_ref().join(entry.file_name()))?;
let info = fs::read_to_string(entry.path())?;
if let Ok(schema) = serde_json::from_str::<Schema>(info.as_str()) {
let mut res = String::new();
res.push_str(
format!(
r#"
Schema {{
path: "{}",
name: Name {{
ar: "{}",
en: "{}",
fr: "{}",
}},
ty: {},"#,
entry
.path()
.to_str()
.unwrap()
.trim_end_matches("/info.json")
.trim_start_matches("../_data/"),
schema.name.ar,
schema.name.en,
schema.name.fr,
schema.ty.to_string()
)
.as_str(),
);
if let Some(terms) = &schema.terms {
res.push_str(
format!(
r#"
terms: Some(Terms {{
per_year: {},
slots: vec![{}],
}})
}},"#,
terms.per_year,
terms
.slots
.iter()
.map(|e| format!("{}", e))
.collect::<Vec<String>>()
.join(", ")
)
.as_str(),
);
} else {
res.push_str(
format!(
r#"
terms: None,
}},"#
)
.as_str(),
);
}
gen_statics.push(res);
*count += 1;
}
}
}
Ok(())
}

fn generate_data_file(schemas: Vec<String>) -> Result<(), io::Error> {
let data = format!(
r##"// This is auto-generated file. Do not edit it manually.

use crate::{{Name, Schema, Terms, Type}};
use lazy_static::lazy_static;

lazy_static! {{
pub static ref ENTRIES: [Schema; {}] = [{}];
}}
"##,
schemas.len(),
schemas.join(""),
);

fs::write("./src/_data.rs", data)?;
Ok(())
}

fn main() {
copy_dir_all(Path::new("../_data"), Path::new("./src/_data")).unwrap();
let mut schemas: Vec<String> = vec![];
let mut count = 0;
gen_static_refs(
Path::new("../_data"),
Path::new("./src/_data"),
&mut schemas,
&mut count,
)
.unwrap();
generate_data_file(schemas).unwrap();
}
37 changes: 37 additions & 0 deletions rust/src/api/get_node_by_path.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
use crate::{Schema, _data::DATA};

pub fn get_node_by_path(path: &str) -> Option<Schema> {
let path = path.trim_start_matches('/');
let path = path.trim_end_matches('/');
let path = path.split('/').collect::<Vec<_>>();

let mut node = DATA.clone();

for part in path {
node = node.get(part)?.clone();
}

let node = node.get("info")?.clone();
let node: Schema = serde_json::from_value(node).unwrap();

Some(node)
}

#[cfg(test)]
mod test {
use crate::api::get_node_by_path::get_node_by_path;

#[test]
fn check_umkb_info() {
let result = get_node_by_path("umkb");

assert_eq!(format!("{:?}", result), "Some(Schema { name: Name { ar: \"جامعة محمد خيضر بسكرة\", en: \"University of Mohamed Khider Biskra\", fr: \"Université Mohamed Khider Biskra\" }, ty: University, terms: None })");
}

#[test]
fn check_non_valid_info() {
let result = get_node_by_path("non-valid");

assert_eq!(format!("{:?}", result), "None");
}
}
1 change: 1 addition & 0 deletions rust/src/api/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod get_node_by_path;
60 changes: 32 additions & 28 deletions rust/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
use std::fs;
#![recursion_limit = "512"]

mod _data;
// pub mod api;

use serde::{Deserialize, Serialize};
use serde_json::json;

static DATA_FOLDER: &'static str = "src/_data";
static CARGO_MANIFEST_DIR: &'static str = env!("CARGO_MANIFEST_DIR");

#[derive(Debug, Serialize, Deserialize)]
pub struct Name {
pub ar: String,
pub en: String,
pub fr: String,
pub struct Name<'a> {
pub ar: &'a str,
pub en: &'a str,
pub fr: &'a str,
}

impl std::fmt::Display for Name {
impl std::fmt::Display for Name<'static> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let obj = json!({"ar": self.ar, "en": self.en, "fr": self.fr});
write!(f, "{}", serde_json::to_string_pretty(&obj).unwrap())
Expand Down Expand Up @@ -71,7 +71,10 @@ impl std::fmt::Display for Terms {

#[derive(Debug, Serialize, Deserialize)]
pub struct Schema {
pub name: Name,
#[serde(skip_serializing)]
pub path: &'static str,
#[serde(borrow)]
pub name: Name<'static>,
#[serde(rename = "type")]
pub ty: Type,
pub terms: Option<Terms>,
Expand All @@ -96,15 +99,13 @@ impl std::fmt::Display for Schema {
}
}

pub fn get_node_by_path(path: &str) -> Option<Schema> {
let fs_path = format!("{}/{}/{}/info.json", CARGO_MANIFEST_DIR, DATA_FOLDER, path);
let Ok(info) = fs::read_to_string(fs_path) else {
return None;
};
let Ok(schema) = serde_json::from_str::<Schema>(info.as_str()) else {
return None;
};
Some(schema)
pub fn get_node_by_path(path: &str) -> Option<&Schema> {
for entry in _data::ENTRIES.iter() {
if entry.path == path {
return Some(entry);
}
}
None
}

#[cfg(test)]
Expand All @@ -128,10 +129,11 @@ mod test {
TestCase::new(
"umkb",
Schema {
path: "umkb",
name: Name {
ar: "جامعة محمد خيضر بسكرة".to_string(),
en: "University of Mohamed Khider Biskra".to_string(),
fr: "Université Mohamed Khider Biskra".to_string(),
ar: "جامعة محمد خيضر بسكرة",
en: "University of Mohamed Khider Biskra",
fr: "Université Mohamed Khider Biskra",
},
ty: Type::University,
terms: None,
Expand All @@ -140,10 +142,11 @@ mod test {
TestCase::new(
"umkb/fst",
Schema {
path: "umkb/fst",
name: Name {
ar: "كلية العلوم والتكنلوجيا".to_string(),
en: "Faculty of Science and Technology".to_string(),
fr: "Faculté des Sciences et de la Technologie".to_string(),
ar: "كلية العلوم والتكنلوجيا",
en: "Faculty of Science and Technology",
fr: "Faculté des Sciences et de la Technologie",
},
ty: Type::Faculty,
terms: None,
Expand All @@ -152,10 +155,11 @@ mod test {
TestCase::new(
"umkb/fst/dee/sec",
Schema {
path: "umkb/fst/dee/sec",
name: Name {
ar: "تخصص التحكم الكهربائي".to_string(),
en: "Specialy of Electrical Control".to_string(),
fr: "Spécialité de commande électrique".to_string(),
ar: "تخصص التحكم الكهربائي",
en: "Specialy of Electrical Control",
fr: "Spécialité de commande électrique",
},
ty: Type::Specialty,
terms: Some(Terms {
Expand Down