From e86f7b2353bb34e3215cda78f7898f26f019ae40 Mon Sep 17 00:00:00 2001 From: Felix Date: Tue, 28 Nov 2023 16:00:12 +0000 Subject: [PATCH] Refactor central ADTs into a core module for modularity This is a refactor in preparation for adding procedural macros in https://github.com/conjure-cp/conjure-oxide/pull/112 Crates that define proc macros can only export proc macros. Therefore, these must be a seperate crate than Conjure Oxide (Conjure Macros). To avoid circular dependencies, datatypes previously defined in Conjure Oxide that are also needed in Conjure Macros have been refactored into a Conjure Core Crate. This creates the following dependency graph: Conjure Core -----> Conjure Macros | | | v ------------------> Conjure Oxide Conjure Oxide will still be the sole "user interface", and will re-export members of core and macros when these should be public facing. Co-authored-by: Niklas Dewally --- .vscode/settings.json | 5 +++-- Cargo.lock | 13 +++++++++++++ Cargo.toml | 1 + conjure_oxide/Cargo.toml | 2 ++ conjure_oxide/src/lib.rs | 6 ++++-- conjure_oxide/src/main.rs | 9 +++++++-- conjure_oxide/src/parse.rs | 8 +------- conjure_oxide/src/solvers/error.rs | 3 +-- conjure_oxide/src/solvers/minion.rs | 15 ++++++--------- conjure_oxide/src/solvers/mod.rs | 10 ++++++++-- conjure_oxide/tests/generated_tests.rs | 3 ++- crates/conjure_core/Cargo.toml | 15 +++++++++++++++ crates/conjure_core/README.md | 4 ++++ {conjure_oxide => crates/conjure_core}/src/ast.rs | 0 crates/conjure_core/src/lib.rs | 4 ++++ .../conjure_core/src/solvers.rs | 0 16 files changed, 71 insertions(+), 27 deletions(-) create mode 100644 crates/conjure_core/Cargo.toml create mode 100644 crates/conjure_core/README.md rename {conjure_oxide => crates/conjure_core}/src/ast.rs (100%) create mode 100644 crates/conjure_core/src/lib.rs rename conjure_oxide/src/solvers/solver_list.rs => crates/conjure_core/src/solvers.rs (100%) diff --git a/.vscode/settings.json b/.vscode/settings.json index 03de4a74d8..cf916d511e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,4 +1,5 @@ -"rust": { +{ + "rust-analyzer.check.command": "check", "editor.defaultFormatter": "rust-lang.rust-analyzer", - "editor.formatOnSave": true + "editor.formatOnSave": true, } diff --git a/Cargo.lock b/Cargo.lock index ceb82d0349..b136434078 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -258,12 +258,25 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +[[package]] +name = "conjure_core" +version = "0.0.1" +dependencies = [ + "serde", + "serde_json", + "serde_with", + "strum", + "strum_macros", + "thiserror", +] + [[package]] name = "conjure_oxide" version = "0.0.1" dependencies = [ "anyhow", "clap", + "conjure_core", "minion_rs", "serde", "serde_json", diff --git a/Cargo.toml b/Cargo.toml index a195dc458b..834320ce16 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,7 @@ resolver = "2" members = [ "conjure_oxide", + "crates/conjure_core", "solvers/kissat", "solvers/minion", "solvers/chuffed", diff --git a/conjure_oxide/Cargo.toml b/conjure_oxide/Cargo.toml index 4cc454eb1e..7015b30122 100644 --- a/conjure_oxide/Cargo.toml +++ b/conjure_oxide/Cargo.toml @@ -9,6 +9,8 @@ default-run = "conjure_oxide" walkdir = "2.4.0" [dependencies] +conjure_core = {path = "../crates/conjure_core" } + serde = { version = "1.0.195", features = ["derive"] } serde_json = "1.0.111" serde_with = "3.4.0" diff --git a/conjure_oxide/src/lib.rs b/conjure_oxide/src/lib.rs index 747851612b..c2c17a283a 100644 --- a/conjure_oxide/src/lib.rs +++ b/conjure_oxide/src/lib.rs @@ -1,8 +1,10 @@ -pub mod ast; pub mod error; pub mod find_conjure; pub mod parse; mod solvers; -pub use ast::Model; +pub use conjure_core::ast; // re-export core::ast as conjure_oxide::ast +pub use conjure_core::ast::Model; // rexport core::ast::Model as conjure_oxide::Model +pub use conjure_core::solvers::Solver; + pub use error::Error; diff --git a/conjure_oxide/src/main.rs b/conjure_oxide/src/main.rs index f60496bc46..6452d82a9b 100644 --- a/conjure_oxide/src/main.rs +++ b/conjure_oxide/src/main.rs @@ -6,7 +6,7 @@ use std::path::PathBuf; use anyhow::Result as AnyhowResult; use clap::{arg, command, Parser}; use conjure_oxide::find_conjure::conjure_executable; -use conjure_oxide::parse::parse_json; +use conjure_oxide::parse::model_from_json; #[derive(Parser)] #[command(author, version, about, long_about = None)] @@ -45,7 +45,12 @@ pub fn main() -> AnyhowResult<()> { let astjson = String::from_utf8(output.stdout)?; - let model = parse_json(&astjson)?; + let model = model_from_json(&astjson)?; println!("{:?}", model); + + // for rule in get_rules_by_kind() { + // println!("Applying rule {:?}", rule); + // } + Ok(()) } diff --git a/conjure_oxide/src/parse.rs b/conjure_oxide/src/parse.rs index 0bfc7bcfd3..fc9b4cf823 100644 --- a/conjure_oxide/src/parse.rs +++ b/conjure_oxide/src/parse.rs @@ -6,7 +6,7 @@ use crate::ast::{DecisionVariable, Domain, Expression, Model, Name, Range}; use crate::error::{Error, Result}; use serde_json::Value as JsonValue; -pub fn parse_json(str: &str) -> Result { +pub fn model_from_json(str: &str) -> Result { let mut m = Model::new(); let v: JsonValue = serde_json::from_str(str)?; let statements = v["mStatements"] @@ -217,9 +217,3 @@ fn parse_constant(constant: &serde_json::Map) -> Option panic!("Unhandled parse_constant {:#?}", otherwise), } } - -impl Model { - pub fn from_json(str: &str) -> Result { - parse_json(str) - } -} diff --git a/conjure_oxide/src/solvers/error.rs b/conjure_oxide/src/solvers/error.rs index b080a4acf2..701816c1d3 100644 --- a/conjure_oxide/src/solvers/error.rs +++ b/conjure_oxide/src/solvers/error.rs @@ -1,7 +1,6 @@ +use crate::Solver; use thiserror::Error; -use super::Solver; - #[derive(Error, Debug)] pub enum SolverError { #[error("not supported in solver `{0}`: `{1}`.")] diff --git a/conjure_oxide/src/solvers/minion.rs b/conjure_oxide/src/solvers/minion.rs index 9e2f43db59..f3eea60952 100644 --- a/conjure_oxide/src/solvers/minion.rs +++ b/conjure_oxide/src/solvers/minion.rs @@ -1,7 +1,7 @@ //! Solver interface to minion_rs. -#[allow(unused_imports)] -use anyhow::anyhow; +use super::{FromConjureModel, SolverError}; +use crate::Solver; use crate::ast::{ DecisionVariable, Domain as ConjureDomain, Expression as ConjureExpression, @@ -12,14 +12,10 @@ use minion_rs::ast::{ Var as MinionVar, VarDomain as MinionDomain, }; -use super::{Solver, SolverError}; - const SOLVER: Solver = Solver::Minion; -impl TryFrom for MinionModel { - type Error = SolverError; - - fn try_from(conjure_model: ConjureModel) -> Result { +impl FromConjureModel for MinionModel { + fn from_conjure(conjure_model: ConjureModel) -> Result { let mut minion_model = MinionModel::new(); // We assume (for now) that the conjure model is fully valid @@ -211,6 +207,7 @@ fn name_to_string(name: ConjureName) -> String { #[cfg(test)] mod tests { + use anyhow::anyhow; use std::collections::HashMap; use minion_rs::ast::VarName; @@ -248,7 +245,7 @@ mod tests { model.constraints.push(leq); model.constraints.push(ineq); - let minion_model = MinionModel::try_from(model)?; + let minion_model = MinionModel::from_conjure(model)?; Ok(minion_rs::run_minion(minion_model, xyz_callback)?) } diff --git a/conjure_oxide/src/solvers/mod.rs b/conjure_oxide/src/solvers/mod.rs index 733306ab94..55bbf4aa8f 100644 --- a/conjure_oxide/src/solvers/mod.rs +++ b/conjure_oxide/src/solvers/mod.rs @@ -1,5 +1,11 @@ mod error; pub mod minion; +pub use crate::ast::Model; pub use error::*; -mod solver_list; -pub use solver_list::*; + +pub trait FromConjureModel +where + Self: Sized, +{ + fn from_conjure(model: Model) -> Result; +} diff --git a/conjure_oxide/tests/generated_tests.rs b/conjure_oxide/tests/generated_tests.rs index b25af0e658..c925ef4ecd 100644 --- a/conjure_oxide/tests/generated_tests.rs +++ b/conjure_oxide/tests/generated_tests.rs @@ -1,4 +1,5 @@ use conjure_oxide::ast::Model; +use conjure_oxide::parse::model_from_json; use serde_json::Value; use std::env; use std::error::Error; @@ -37,7 +38,7 @@ fn integration_test(path: &str, essence_base: &str) -> Result<(), Box let astjson = String::from_utf8(output.stdout)?; // "parsing" astjson as Model - let generated_mdl = Model::from_json(&astjson)?; + let generated_mdl = model_from_json(&astjson)?; // a consistent sorting of the keys of json objects // only required for the generated version diff --git a/crates/conjure_core/Cargo.toml b/crates/conjure_core/Cargo.toml new file mode 100644 index 0000000000..bc4f966102 --- /dev/null +++ b/crates/conjure_core/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "conjure_core" +version = "0.0.1" +edition = "2021" + +[dependencies] +serde = { version = "1.0.192", features = ["derive"] } +serde_json = "1.0.108" +serde_with = "3.4.0" +strum = "0.25.0" +strum_macros = "0.25.3" +thiserror = "1.0.50" + +[lints] +workspace = true diff --git a/crates/conjure_core/README.md b/crates/conjure_core/README.md new file mode 100644 index 0000000000..5599950e63 --- /dev/null +++ b/crates/conjure_core/README.md @@ -0,0 +1,4 @@ +Core datatypes for use in Conjure Oxide. + +This crate is internal to conjure_oxide, and should not be treated as a stable +API. Relevant types are re-exported through conjure_oxide. diff --git a/conjure_oxide/src/ast.rs b/crates/conjure_core/src/ast.rs similarity index 100% rename from conjure_oxide/src/ast.rs rename to crates/conjure_core/src/ast.rs diff --git a/crates/conjure_core/src/lib.rs b/crates/conjure_core/src/lib.rs new file mode 100644 index 0000000000..6471a8b4fb --- /dev/null +++ b/crates/conjure_core/src/lib.rs @@ -0,0 +1,4 @@ +pub mod ast; + +pub mod solvers; +pub use solvers::Solver; diff --git a/conjure_oxide/src/solvers/solver_list.rs b/crates/conjure_core/src/solvers.rs similarity index 100% rename from conjure_oxide/src/solvers/solver_list.rs rename to crates/conjure_core/src/solvers.rs