Skip to content

Instantly share code, notes, and snippets.

@peacememories
Created January 3, 2020 15:35
Show Gist options
  • Save peacememories/a16c4a0d65adf9886fd54d220580391c to your computer and use it in GitHub Desktop.
Save peacememories/a16c4a0d65adf9886fd54d220580391c to your computer and use it in GitHub Desktop.
Example of clingo symbol conversion.
use clingo::{Control, MModel, Part, Symbol};
use std::collections::HashMap;
use failure::{err_msg, Error, Fail};
use std::convert::{TryFrom, TryInto};
pub type Locale = String;
pub type Names = HashMap<Locale, String>;
#[derive(Clone, Debug)]
pub enum CurriculumType {
Bsc,
Msc,
Phd,
}
#[derive(Debug)]
pub struct Curriculum {
pub id: String,
pub names: Names,
pub type_: CurriculumType,
pub exam_groups: Vec<ExamGroup>,
}
#[derive(Debug, Serialize)]
pub struct ExamGroup {
pub id: String,
pub names: Names,
pub modules: Vec<Module>,
}
#[derive(Clone, Debug)]
pub enum ModuleType {
Mandatory,
Elective,
}
#[derive(Debug)]
pub struct Module {
pub id: String,
pub names: Names,
pub type_: ModuleType,
pub min_ec: CentiEc,
pub courses: Vec<Course>,
}
#[derive(Clone, Debug)]
pub enum CourseType {
VU,
UE,
VO,
PR,
SE,
}
#[derive(Debug)]
pub struct Course {
pub id: String,
pub names: Names,
pub ec: CentiEc,
pub type_: CourseType,
}
pub type CentiEc = u16;
impl TryFrom<&Symbol> for CurriculumType {
type Error = Error;
fn try_from(from: &Symbol) -> Result<Self, Self::Error> {
match from.name()? {
"bsc" => Ok(Self::Bsc),
"msc" => Ok(Self::Msc),
"phd" => Ok(Self::Phd),
_ => Err(err_msg(format!(
"Unexpected curriculum type: {}",
from.name()?
))),
}
}
}
impl TryFrom<&Symbol> for ModuleType {
type Error = Error;
fn try_from(from: &Symbol) -> Result<Self, Self::Error> {
match from.name()? {
"mandatory" => Ok(Self::Mandatory),
"elective" => Ok(Self::Elective),
_ => Err(err_msg("Unexpected module type")),
}
}
}
impl TryFrom<&Symbol> for CourseType {
type Error = Error;
fn try_from(from: &Symbol) -> Result<Self, Self::Error> {
match from.name()? {
"ctype_VO" => Ok(Self::VO),
"ctype_UE" => Ok(Self::UE),
"ctype_VU" => Ok(Self::VU),
"ctype_PR" => Ok(Self::PR),
"ctype_SE" => Ok(Self::SE),
_ => Err(err_msg(format!("Unexpected course type: {}", from.name()?))),
}
}
}
enum ResSym {
Curriculum {
key: String,
id: String,
},
CurriculumType {
key: String,
type_: CurriculumType,
},
CurriculumName {
key: String,
lang: String,
string: String,
},
ExamGroup {
key: String,
},
ExamGroupName {
key: String,
lang: String,
string: String,
},
PartOfCurriculum {
exam_group: String,
curriculum: String,
},
Module {
key: String,
},
ModuleName {
key: String,
lang: String,
string: String,
},
PartOfExamgroup {
module: String,
exam_group: String,
},
ModuleType {
key: String,
type_: ModuleType,
},
ModuleMinEc {
key: String,
ects: CentiEc,
},
Course {
key: String,
},
CourseEc {
key: String,
ects: CentiEc,
},
CourseType {
key: String,
type_: CourseType,
},
PartOfModule {
course: String,
module: String,
},
CourseName {
key: String,
lang: String,
string: String,
},
}
#[derive(Debug)]
enum ResSymError {
NotRecognized,
Nested(Error),
}
impl From<Error> for ResSymError {
fn from(from: Error) -> Self {
Self::Nested(from)
}
}
impl From<clingo::ClingoError> for ResSymError {
fn from(from: clingo::ClingoError) -> Self {
Self::Nested(from.into())
}
}
impl Display for ResSymError {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
match self {
Self::NotRecognized => write!(f, "Unrecognized symbol"),
Self::Nested(error) => error.fmt(f),
}
}
}
impl Fail for ResSymError {}
impl TryFrom<&Symbol> for ResSym {
type Error = ResSymError;
fn try_from(symbol: &Symbol) -> Result<Self, Self::Error> {
use ResSym::*;
let arguments = symbol.arguments()?;
match symbol.name()? {
"curriculum" => Ok(Curriculum {
key: arguments
.get(0)
.ok_or(err_msg("Not enough arguments"))?
.name()?
.into(),
id: arguments
.get(1)
.ok_or(err_msg("Not enough arguments"))?
.string()?
.into(),
}),
"curriculum_name" => Ok(CurriculumName {
key: arguments
.get(0)
.ok_or(err_msg("Not enough arguments"))?
.name()?
.into(),
lang: arguments
.get(1)
.ok_or(err_msg("Not enough arguments"))?
.name()?
.into(),
string: arguments
.get(2)
.ok_or(err_msg("Not enough arguments"))?
.string()?
.into(),
}),
"curriculum_type" => Ok(CurriculumType {
key: arguments
.get(0)
.ok_or(err_msg("Not enough arguments"))?
.name()?
.into(),
type_: arguments
.get(1)
.ok_or(err_msg("Not enough arguments"))?
.try_into()?,
}),
"examgroup" => Ok(ExamGroup {
key: arguments
.get(0)
.ok_or(err_msg("Not enough arguments"))?
.name()?
.into(),
}),
"examgroup_name" => Ok(ExamGroupName {
key: arguments
.get(0)
.ok_or(err_msg("Not enough arguments"))?
.name()?
.into(),
lang: arguments
.get(1)
.ok_or(err_msg("Not enough arguments"))?
.name()?
.into(),
string: arguments
.get(2)
.ok_or(err_msg("Not enough arguments"))?
.string()?
.into(),
}),
"part_of_curriculum" => Ok(PartOfCurriculum {
exam_group: arguments
.get(0)
.ok_or(err_msg("Not enough arguments"))?
.name()?
.into(),
curriculum: arguments
.get(1)
.ok_or(err_msg("Not enough arguments"))?
.name()?
.into(),
}),
"module" => Ok(Module {
key: arguments
.get(0)
.ok_or(err_msg("Not enough arguments"))?
.name()?
.into(),
}),
"module_name" => Ok(ModuleName {
key: arguments
.get(0)
.ok_or(err_msg("Not enough arguments"))?
.name()?
.into(),
lang: arguments
.get(1)
.ok_or(err_msg("Not enough arguments"))?
.name()?
.into(),
string: arguments
.get(2)
.ok_or(err_msg("Not enough arguments"))?
.string()?
.into(),
}),
"part_of_examgroup" => Ok(PartOfExamgroup {
module: arguments
.get(0)
.ok_or(err_msg("Not enough arguments"))?
.name()?
.into(),
exam_group: arguments
.get(1)
.ok_or(err_msg("Not enough arguments"))?
.name()?
.into(),
}),
"module_type" => Ok(ModuleType {
key: arguments
.get(0)
.ok_or(err_msg("Not enough arguments"))?
.name()?
.into(),
type_: arguments
.get(1)
.ok_or(err_msg("Not enough arguments"))?
.try_into()?,
}),
"module_min_cects" => Ok(ModuleMinEc {
key: arguments
.get(0)
.ok_or(err_msg("Not enough arguments"))?
.name()?
.into(),
ects: arguments
.get(1)
.ok_or(err_msg("Not enough arguments"))?
.number()? as u16,
}),
"course" => Ok(Course {
key: arguments
.get(0)
.ok_or(err_msg("Not enough arguments"))?
.name()?
.into(),
}),
"course_cects" => Ok(CourseEc {
key: arguments
.get(0)
.ok_or(err_msg("Not enough arguments"))?
.name()?
.into(),
ects: arguments
.get(1)
.ok_or(err_msg("Not enough arguments"))?
.number()? as u16,
}),
"course_type" => Ok(CourseType {
key: arguments
.get(0)
.ok_or(err_msg("Not enough arguments"))?
.name()?
.into(),
type_: arguments
.get(1)
.ok_or(err_msg("Not enough arguments"))?
.try_into()?,
}),
"part_of_module" => Ok(PartOfModule {
course: arguments
.get(0)
.ok_or(err_msg("Not enough arguments"))?
.name()?
.into(),
module: arguments
.get(1)
.ok_or(err_msg("Not enough arguments"))?
.name()?
.into(),
}),
"course_name" => Ok(CourseName {
key: arguments
.get(0)
.ok_or(err_msg("Not enough arguments"))?
.name()?
.into(),
lang: arguments
.get(1)
.ok_or(err_msg("Not enough arguments"))?
.name()?
.into(),
string: arguments
.get(2)
.ok_or(err_msg("Not enough arguments"))?
.string()?
.into(),
}),
_ => Err(ResSymError::NotRecognized),
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment