Skip to content

Commit

Permalink
feature/initial support for rust (#35)
Browse files Browse the repository at this point in the history
* initial support for parsing mps files using Rust
- currently we support default persistency and file-per-root persistency
---------

Co-authored-by: Micahel Langhammer <[email protected]>
  • Loading branch information
danielratiu and MLanghammer authored Jul 28, 2024
1 parent 31dfa1c commit 35818ec
Show file tree
Hide file tree
Showing 32 changed files with 1,328 additions and 4 deletions.
26 changes: 26 additions & 0 deletions .github/workflows/mps_cli_rs_build.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: MPS-CLI-RS_CI

on:
push:
branches:
- 'main'
pull_request:
workflow_dispatch:

env:
GITHUB_TOKEN: ${{ secrets.MPSCLI_GITHUB_PKG_REGISTRY }}

jobs:
build_mps_cli_rs:
runs-on: ubuntu-latest
env:
DISPLAY: ':99'

steps:
- uses: actions/checkout@v3
- uses: hecrj/setup-rust-action@v1
with:
rust-version: stable
- name: Run tests
working-directory: ./mps-cli-rs
run: cargo test
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
**/venv/
**/node_modules/
**/dist/
/mps-cli-rs/target

gradle.properties
**/workspace.xml
Expand Down
3 changes: 2 additions & 1 deletion Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ This repository contains tooling for reading MPS models from command line - with
### Repository Structure
- `mps-cli-gradle-plugin` - the gradle plugin to read MPS models
- `mps-cli-py` - a Python library to read MPS models
- `mps-cli-ts` - a Typescript library to read MPS models
- `mps-cli-ts` - a Typescript library to read MPS models
- `mps-cli-ts` - a Rust library to read MPS models
- `demos` - examples for the use of the MPS-CLI tooling
- `gradle-plugin-use` - example of the use of the `mps-cli-gradle-plugin`
- `jupyter-notebook` - example of the use of the `mps-cli-py` library in a Jupyter Notebook
Expand Down
10 changes: 9 additions & 1 deletion mps-cli-py/.idea/workspace.xml

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

5 changes: 3 additions & 2 deletions mps-cli-py/src/mpscli/demo.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import sys
sys.path.insert(1, '..')

from model.builder.SSolutionsRepositoryBuilder import SSolutionsRepositoryBuilder

builder = SSolutionsRepositoryBuilder()
#repo = builder.build('..\\..\\mps_test_projects\\mps_cli_lanuse_file_per_root')
repo = builder.build('..\\..\\..\\..\\E3_2.0_Solution\\solutions')
repo = builder.build('..\\..\\mps_test_projects\\mps_cli_lanuse_file_per_root')
7 changes: 7 additions & 0 deletions mps-cli-rs/.vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"rust-analyzer.linkedProjects": [
"./Cargo.toml",
"./Cargo.toml",
"./Cargo.toml"
]
}
67 changes: 67 additions & 0 deletions mps-cli-rs/Cargo.lock

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

22 changes: 22 additions & 0 deletions mps-cli-rs/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[package]
name = "mps-cli"
version = "0.1.0"
edition = "2021"
license = "Eclipse Public License - v 2.0"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[lib]
path = "src/lib.rs"

[features]
default = []
std = []

[dependencies]
walkdir = "2.5.0"
roxmltree = "0.20.0"

[profile.release]
lto = "fat"
codegen-units = 1
7 changes: 7 additions & 0 deletions mps-cli-rs/src/builder/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
pub(crate) mod smodules_repository_builder;
mod ssolution_builder;
mod smodel_builder_base;
mod smodel_builder_default_persistency;
mod smodel_builder_file_per_root_persistency;
mod slanguage_builder;
mod node_id_utils;
56 changes: 56 additions & 0 deletions mps-cli-rs/src/builder/node_id_utils.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
use std::collections::HashMap;

struct NodeIdEncodingUtils {
my_index_chars : String,
min_char : u8,
my_char_to_value : HashMap<usize, usize>,
}

impl NodeIdEncodingUtils {
pub(crate) fn new() -> Self {
let my_index_chars = String::from("0123456789abcdefghijklmnopqrstuvwxyz$_ABCDEFGHIJKLMNOPQRSTUVWXYZ");
let min_char = '$' as u8;
let mut my_char_to_value : HashMap<usize, usize> = HashMap::new();
let bytes = my_index_chars.as_bytes();
for i in 0..my_index_chars.len() {
let char_value = bytes[i] as u8;
let ii: usize = (char_value - min_char) as usize;
my_char_to_value.insert(ii, i);
}

NodeIdEncodingUtils {
my_index_chars : my_index_chars,
min_char : min_char,
my_char_to_value : my_char_to_value,
}
}

pub(crate) fn decode(&self, uid_string : String) -> String {
let mut res = 0;
let bytes = uid_string.as_bytes();
let mut c = bytes[0];
let ii : usize = (c as u8 - self.min_char) as usize;
let mut value = self.my_char_to_value[&ii];
res = value;
for idx in 1..uid_string.len() {
res = res << 6;
c = bytes[idx];
value = self.my_index_chars.find(c as char).unwrap();
res = res | value;
}
return res.to_string();
}

}

#[cfg(test)]
mod tests {
use crate::builder::node_id_utils::NodeIdEncodingUtils;

#[test]
fn test_conversion() {
let node_id_utils = NodeIdEncodingUtils::new();

assert_eq!("5731700211660045983", node_id_utils.decode(String::from("4Yb5JA31NUv")));
}
}
20 changes: 20 additions & 0 deletions mps-cli-rs/src/builder/playground.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use std::cell::RefCell;
use std::rc::Rc;

struct Person {
name: String,
}

struct Company {
employees: RefCell<Vec<Rc<Person>>>,
}

impl Company {
fn search_employee(&self, name: &str) -> Option<Rc<Person>> {
self.employees
.borrow()
.iter()
.find(|employee| employee.name == name)
.map(|employee| Rc::clone(employee))
}
}
57 changes: 57 additions & 0 deletions mps-cli-rs/src/builder/slanguage_builder.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;

use crate::model::sconcept::{SConcept, SContainmentLink, SProperty, SReferenceLink};
use crate::model::slanguage::SLanguage;


pub(crate) struct SLanguageBuilder {
pub concept_id_to_concept : RefCell<HashMap<String, Rc<SConcept>>>,
}

impl<'a> SLanguageBuilder {
pub(crate) fn new() -> Self {
SLanguageBuilder {
concept_id_to_concept: RefCell::new(HashMap::new()),
}
}

pub(crate) fn get_or_create_concept(&self, language: &mut SLanguage, concept_id: &str, concept_name: &str) -> Rc<SConcept> {
let mut concept_id_to_concept = self.concept_id_to_concept.borrow_mut();
let concept = concept_id_to_concept.get(concept_id);
if let Some(c) = concept {
return Rc::clone(c);
}

let concept = SConcept::new(concept_name.to_string(), concept_id.to_string());
let rc = Rc::new(concept);
concept_id_to_concept.insert(concept_id.to_string(), rc.clone());
language.concepts.push(rc.clone());
rc
}


pub(crate) fn get_or_create_property(&'a self, concept: Rc<SConcept>, property_id: String, property_name: String) -> Rc<SProperty> {
let mut props = concept.properties.borrow_mut();
let property = props.entry(property_id.clone()).or_insert(Rc::new(SProperty::new(property_name, property_id)));
Rc::clone(property)
}

pub(crate) fn get_or_create_child(&'a self, concept: Rc<SConcept>, child_id: String, child_name: String) -> Rc<SContainmentLink> {
let mut links = concept.containment_links.borrow_mut();
let containment_link = links.entry(child_id.clone()).or_insert(Rc::new(SContainmentLink::new(child_name, child_id)));
Rc::clone(containment_link)
}

pub(crate) fn get_or_create_reference(&'a self, concept: Rc<SConcept>, reference_id: String, reference_name: String) -> Rc<SReferenceLink> {
let mut refs = concept.reference_links.borrow_mut();
let reference_link = refs.entry(reference_id.clone()).or_insert(Rc::new(SReferenceLink::new(reference_name, reference_id)));
Rc::clone(reference_link)
}

}

pub(crate) fn get_or_build_language<'a>(language_id: &String, language_name: &String, language_id_to_slanguage: &'a mut HashMap<String, SLanguage>) -> &'a mut SLanguage {
language_id_to_slanguage.entry(language_id.to_string()).or_insert_with(|| SLanguage::new(language_name.to_string(), language_id.to_string()))
}
Loading

0 comments on commit 35818ec

Please sign in to comment.