use std::str::FromStr;
#[derive(Default)]
enum LexerToken {
#[default] None,
Equal,
Lbrace,
Rbrace,
Identifier(String),
}
#[derive(Default)]
struct LexerState<'a> {
pub data: &'a str,
pub tokens: Vec<LexerToken>,
}
impl<'a> LexerState<'a> {
pub fn do_lex(&mut self) {
let bytes = self.data.bytes();
let mut iter = bytes.into_iter().peekable();
while iter.len() > 0 {
let mut c = *iter.peek().unwrap();
match c {
b'=' => {
iter.next();
self.tokens.push(LexerToken::Equal)
},
b'{' => {
iter.next();
self.tokens.push(LexerToken::Lbrace)
},
b'}' => {
iter.next();
self.tokens.push(LexerToken::Rbrace)
},
b'#' => {
iter.next();
while iter.len() > 0 {
if c == b'\r' || c == b'\n' {
break;
}
c = iter.next().unwrap();
}
},
b' ' | b'\t' | b'\r' | b'\n' => {
iter.next();
},
_ => {
let s_iter = iter.clone();
let s = String::from_iter(s_iter
.take_while(|&x| !(x == b' ' || x == b'\t' || x == b'\r' || x == b'\n' || x == b'=') )
.map(|x| x as char )
);
iter.nth(s.len());
self.tokens.push(LexerToken::Identifier(s));
}
}
}
}
pub fn from_memory(data: &'a str) -> Self {
let mut s = Self{
data: data,
tokens: Vec::new()
};
s.do_lex();
s
}
}
#[derive(Default)]
struct Property {
name: String,
value: String,
borrow_only: bool,
}
#[derive(Default)]
struct Group {
name: String,
size: usize,
default_save: String,
relation: bool,
erasable: bool,
first: String,
first_name: String,
second: String,
second_name: String,
adjacency: bool,
bilateral: bool,
unilateral: bool,
adj_type: String,
properties: Vec<Property>
}
#[derive(Default)]
struct Root {
groups: Vec<Group>
}
#[derive(Default)]
struct State<'a> {
lexer: LexerState<'a>
}
impl<'a> State<'a> {
fn parse(
&self,
root: &mut Root,
mut iter: std::slice::Iter<'a, LexerToken>,
) -> std::slice::Iter<'a, LexerToken> {
let mut last_key: Option<&String> = None;
while iter.len() > 0 {
let t = iter.next().unwrap();
match t {
LexerToken::Identifier(ident) => {
if last_key.is_some() {
let last_group: &mut Group = root.groups.last_mut().unwrap();
if last_key.unwrap().starts_with("@size") {
last_group.size = ident.parse::<usize>().unwrap();
} else if last_key.unwrap().starts_with("@serde") {
last_group.default_save = ident.clone();
} else if last_key.unwrap().starts_with("@erasable") {
last_group.erasable = true;
} else if last_key.unwrap().starts_with("@firstName") {
last_group.first_name = ident.clone();
} else if last_key.unwrap().starts_with("@secondName") {
last_group.second_name = ident.clone();
} else if last_key.unwrap().starts_with("@first") {
last_group.first = ident.clone();
} else if last_key.unwrap().starts_with("@second") {
last_group.second = ident.clone();
} else if last_key.unwrap().starts_with("@relation") {
last_group.relation = true;
} else if last_key.unwrap().starts_with("@adjacency") {
last_group.adjacency = true;
} else if last_key.unwrap().starts_with("@unilateral") {
last_group.unilateral = true;
} else if last_key.unwrap().starts_with("@bilateral") {
last_group.bilateral = true;
} else if last_key.unwrap().starts_with("@adjType") {
last_group.adj_type = ident.clone();
} else if last_key.unwrap().starts_with("[borrow]") {
let mut prop = Property::default();
prop.name = last_key.unwrap().clone().split_off(8);
prop.value = ident.clone();
prop.borrow_only = true;
last_group.properties.push(prop);
} else {
let mut prop = Property::default();
prop.name = last_key.unwrap().clone();
prop.value = ident.clone();
last_group.properties.push(prop);
}
last_key = None;
} else {
last_key = Some(ident);
}
},
LexerToken::Lbrace => {
let mut group = Group::default();
group.name = last_key.unwrap().to_string();
root.groups.push(group);
last_key = None;
},
LexerToken::Rbrace => {
last_key = None;
},
_ => {},
}
}
iter
}
fn do_parse(
&mut self
) -> Root {
let mut root = Root::default();
self.lexer.do_lex();
let iter = self.lexer.tokens.iter();
let res = self.parse(&mut root, iter);
assert!(res.len() == 0); root
}
fn from_str(s: &'a str) -> Self {
Self{
lexer: LexerState{
data: s,
tokens: Vec::default(),
}
}
}
fn to_func_name(s: &str) -> String {
if s == "@global" {
String::from_str("global").unwrap()
} else {
let mut ns = String::new();
for c in s.chars().enumerate() {
if c.0 > 0 && c.1.is_uppercase() { ns.push('_'); }
ns.push_str(c.1.to_lowercase().to_string().as_str());
}
ns
}
}
fn to_fish_type_name(s: &str) -> String {
let mut ns = String::new();
for c in s.chars().enumerate() {
if c.1 == '<' {
ns.push(':'); ns.push(':');
}
ns.push_str(c.1.to_string().as_str());
}
ns
}
fn get_prim_type(size: usize, ub: bool) -> &'static str {
if size <= i8::MAX as usize && !ub {
"u8"
} else if size <= i16::MAX as usize && !ub {
"u16"
} else {
assert!(size <= i32::MAX as usize);
"u32"
}
}
pub fn mt_safe() -> bool {
true
}
pub fn matrix_triangle_size(gsize: usize) -> usize {
let n = (gsize - 1) as f32;
let a = 1.0f32;
let d = 1.0f32;
((n / 2.0) * (2.0 * a + (n - 1.0) * d) / 32.0).ceil() as usize
}
pub fn get_node_by_name(name: &String, root: &'a Root) -> Option<&'a Group> {
root.groups
.iter()
.find(|&x| x.name == *name)
}
pub fn print_root<W>(
w: &mut W,
root: &'a Root
) -> Result<(), Box<dyn std::error::Error>>
where
W: std::io::Write
{
let clippy = "#[optimize(size)]";
write!(w, "#[allow(clippy::all)]\n")?;
write!(w, "#[allow(unused_braces)]\n")?;
write!(w, "use viffy;\n")?;
write!(w, "use viffy::make_typed_id;\n")?;
write!(w, "use viffy::prelude::*;\n")?;
write!(w, "use rayon::prelude::*;\n")?;
let mut serde_tags = std::collections::BTreeSet::new();
for g in &root.groups {
serde_tags.insert(g.default_save.clone());
}
write!(w, "#[repr(u8)]\n")?;
write!(w, "#[derive(Default, Debug, PartialEq, Eq, PartialOrd, Ord)]\n")?;
write!(w, "pub enum SerializationTag {{\n")?;
for (index, e) in serde_tags.iter().enumerate() {
let (left, right) = e.split_at(1);
let pref = if index == 0 { "#[default]" } else { "" };
write!(w, " {pref}{}{right} = {index},\n", left.to_uppercase())?;
}
write!(w, "}}\n")?;
write!(w, "fn linear_matrix_index(ni: usize, ii: usize, ji: usize) -> usize {{\n")?;
write!(w, " let n = ni as f32; let i = ii as f32; let j = ji as f32;\n")?;
write!(w," ((n * (n - 1.0) / 2.0) - (n - i) * ((n - i) - 1.0) / 2.0 + j - i - 1.0).ceil() as usize")?;
write!(w, "}}\n")?;
for g in &root.groups {
if g.name == "@global" {
write!(w, "#[derive(Default)]\n")?;
write!(w, "pub struct GlobalContainer {{\n")?;
write!(w, " //single element data\n")?;
for p in &g.properties {
write!(w, " m_{}: {},\n", p.name, p.value)?;
}
write!(w, "}}\n")?;
} else {
let id_prim_type = Self::get_prim_type(g.size, g.bilateral | g.unilateral);
write!(w, "make_typed_id!({}Id, {id_prim_type});\n", g.name)?;
write!(w, "struct {}Container {{\n", g.name)?;
if g.erasable {
write!(w, " m_free_list: viffy::FixedBitmap::<{}>,\n", (g.size + 3) / 4)?;
}
write!(w, " m_size: usize,\n")?;
if g.unilateral || g.bilateral {
write!(w, " m_set_list: Vec<std::collections::BTreeSet<{}Id>>,\n", g.adj_type)?;
for p in &g.properties {
write!(w, " /*ul*/m_{}: std::collections::BTreeMap<{}Id, {}>,\n", p.name, g.name, p.value)?;
}
} else {
if g.relation {
write!(w, " m_{}: [{}Id; {}],\n", g.first_name, g.first, g.size)?;
}
for p in &g.properties {
if p.borrow_only {
write!(w, " m_{}: Vec<{}>,\n", p.name, p.value)?;
} else {
write!(w, " m_{}: [{}; {}],\n", p.name, p.value, g.size)?;
}
}
for og in &root.groups {
let func_name = Self::to_func_name(og.name.as_str());
if og.relation && og.first == g.name {
write!(w, " /*relation*/m_{func_name}: Vec<Vec<{}Id>>,\n", og.name)?;
} else if og.adjacency && og.adj_type == g.name {
let sn = Self::matrix_triangle_size(g.size);
write!(w, " /*adjacency*/m_{func_name}: [u32; {sn}],\n")?;
}
}
}
write!(w, "}}\n")?;
}
}
write!(w, "pub struct World {{\n")?;
for g in &root.groups {
if g.name == "@global" {
write!(w, " /*global*/m_global: GlobalContainer,\n")?;
} else {
let fn_name = Self::to_func_name(g.name.as_str());
write!(w, " m_{fn_name}: {}Container,\n", g.name)?;
}
}
write!(w, "}}\n")?;
write!(w, "impl Serializable for World {{\n")?;
write!(w, " fn serialize(&self, s: &mut Serializer) {{\n")?;
for g in &root.groups {
if g.name == "@global" {
for p in &g.properties {
write!(w, " self.m_global.m_{}.serialize(s);\n", p.name)?;
}
continue; }
let fn_name = Self::to_func_name(g.name.as_str());
for p in &g.properties {
write!(w, " self.m_{fn_name}.m_{}.serialize(s);\n", p.name)?;
}
}
write!(w, " }}\n")?;
write!(w, " fn deserialize(&mut self, s: &mut Serializer) {{\n")?;
for g in &root.groups {
if g.name == "@global" {
for p in &g.properties {
write!(w, " self.m_global.m_{}.deserialize(s);\n", p.name)?;
}
continue;
}
let fn_name = Self::to_func_name(g.name.as_str());
for p in &g.properties {
write!(w, " self.m_{fn_name}.m_{}.deserialize(s);\n", p.name)?;
}
}
write!(w, " }}\n")?;
write!(w, "}}\n")?;
write!(w, "impl World {{\n")?;
write!(w, " {clippy} pub unsafe fn write_new(&mut self) {{\n")?;
for g in &root.groups {
let fn_name = Self::to_func_name(g.name.as_str());
if g.name == "@global" {
for p in &g.properties {
let fish_name = Self::to_fish_type_name(p.value.as_str());
write!(w, " self.m_{fn_name}.m_{} = {fish_name}::default();\n", p.name)?;
}
} else {
write!(w, " self.m_{fn_name}.m_size = 0;\n")?;
if g.erasable {
write!(w, " self.m_{fn_name}.m_free_list = viffy::FixedBitmap::default();\n")?;
}
if g.unilateral || g.bilateral {
let adj_size = Self::get_node_by_name(&g.adj_type, root)
.expect(format!("unable to find {}", g.adj_type).as_str())
.size;
write!(w, " self.m_{fn_name}.m_set_list = vec![std::collections::BTreeSet::default(); {adj_size}];\n")?;
for p in &g.properties {
write!(w, " /*ul*/self.m_{fn_name}.m_{} = std::collections::BTreeMap::default();\n", p.name)?;
}
} else {
if g.relation {
write!(w, " self.m_{fn_name}.m_{} = [{}Id::default(); {}];\n", g.first_name, g.first, g.size)?;
}
for p in &g.properties {
let fish_name = Self::to_fish_type_name(p.value.as_str());
if p.borrow_only {
write!(w, " self.m_{fn_name}.m_{} = vec![{fish_name}::default(); {}];\n", p.name, g.size)?;
} else {
write!(w, " self.m_{fn_name}.m_{} = [{fish_name}::default(); {}];\n", p.name, g.size)?;
}
}
for og in &root.groups {
let func_name = Self::to_func_name(og.name.as_str());
if og.relation && og.first == g.name {
write!(w, " /*relation*/self.m_{fn_name}.m_{func_name} = vec![Vec::default(); {}];\n", g.size)?;
} else if og.adjacency && og.adj_type == g.name {
let sn = Self::matrix_triangle_size(g.size);
write!(w, " /*adjacency*/self.m_{fn_name}.m_{func_name} = [0; {sn}];\n")?;
}
}
}
}
}
write!(w, " }}\n")?;
write!(w, "{clippy} pub fn reset(&mut self) {{\n")?;
write!(w, " unsafe {{ self.write_new() }};\n")?;
write!(w, "}}")?;
for g in &root.groups {
if g.name == "@global" {
for p in &g.properties {
if p.borrow_only {
write!(w, " {clippy} pub fn get_global_{}(&self) -> &{} {{\n", p.name, p.value)?;
write!(w, " /*unsafe*/{{ &self.m_global.m_{} }}\n", p.name)?;
write!(w, " }}\n")?;
write!(w, " {clippy} pub fn get_mut_global_{}(&mut self) -> &mut {} {{\n", p.name, p.value)?;
write!(w, " /*unsafe*/{{ &mut self.m_global.m_{} }}\n", p.name)?;
write!(w, " }}\n")?;
} else {
write!(w, " {clippy} pub fn get_global_{}(&self) -> {} {{\n", p.name, p.value)?;
write!(w, " /*unsafe*/{{ self.m_global.m_{} }}\n", p.name)?;
write!(w, " }}\n")?;
write!(w, " {clippy} pub fn set_global_{}(&mut self, v: &{}) {{\n", p.name, p.value)?;
write!(w, " /*unsafe*/{{ self.m_global.m_{} = *v; }}\n", p.name)?;
write!(w, " }}\n")?;
}
}
continue;
}
let id_prim_type = Self::get_prim_type(g.size, g.bilateral | g.unilateral);
let fn_name = Self::to_func_name(g.name.as_str());
if g.adjacency || g.unilateral || g.bilateral {
let rel_fn_name = Self::to_func_name(&g.adj_type);
if g.unilateral || g.bilateral {
if g.unilateral {
write!(w, " {clippy} pub fn get_{fn_name}_by_pair(&self, a: {}Id, b: {}Id) -> {}Id {{\n", g.adj_type, g.adj_type, g.name)?;
write!(w, " {}Id::from(((b.get_value() as {id_prim_type}) << 16) | (a.get_value() as {id_prim_type}))\n", g.name)?;
write!(w, " }}\n")?;
} else {
write!(w, " {clippy} pub fn get_{fn_name}_by_pair(&self, a: {}Id, b: {}Id) -> {}Id {{\n", g.adj_type, g.adj_type, g.name)?;
write!(w, " {}Id::from(((b.get_value().max(a.get_value()) as {id_prim_type}) << 16) | (a.get_value().min(b.get_value()) as {id_prim_type}))\n", g.name)?;
write!(w, " }}\n")?;
}
write!(w, " {clippy} pub fn get_{fn_name}_index(&self, id: {}Id, index: usize) -> {}Id {{\n", g.name, g.adj_type)?;
write!(w, " (match index {{ 0 => id.get_value() & 0xffff, _ => id.get_value() >> 16 }}).into()\n")?;
write!(w, " }}\n")?;
write!(w, " {clippy} pub fn get_{fn_name}_other(&self, id: {}Id, me: {}Id) -> {}Id {{\n", g.name, g.adj_type, g.adj_type)?;
write!(w, " self.get_{fn_name}_index(id, if self.get_{fn_name}_index(id, 0) == me {{ 1 }} else {{ 0 }})\n")?;
write!(w, " }}\n")?;
write!(w, " {clippy} pub fn create_{fn_name}_by_pair(&mut self, a: {}Id, b: {}Id) -> {}Id {{\n", g.adj_type, g.adj_type, g.name)?;
write!(w, " let id = self.get_{fn_name}_by_pair(a, b);\n")?;
write!(w, " self.m_{fn_name}.m_set_list[(id.get_value() & 0xffff) as usize].insert(b);\n")?;
write!(w, " id\n")?;
write!(w, " }}\n")?;
write!(w, " {clippy} pub fn for_each_{fn_name}<F: FnMut(&Self, {}Id)>(&self, mut f: F) {{\n", g.name)?;
write!(w, " for (a, v) in self.m_{fn_name}.m_set_list.iter().enumerate() {{\n")?;
write!(w, " for &b in v.iter() {{ f(self, self.get_{fn_name}_by_pair((a as u32).into(), b)); }}\n")?;
write!(w, " }}\n")?;
write!(w, " }}\n")?;
write!(w, " {clippy} pub fn for_each_{fn_name}_in_{rel_fn_name}<F: FnMut(&Self, {}Id)>(&self, id: {}Id, mut f: F) {{\n", g.name, g.adj_type)?;
write!(w, " for &k in self.m_{fn_name}.m_set_list[id.get_value() as usize].iter() {{\n")?;
write!(w, " f(self, self.get_{fn_name}_by_pair(id, k));\n")?;
write!(w, " }}\n")?;
write!(w, " }}\n")?;
}
} else {
if g.erasable && g.relation {
write!(w, " {clippy} fn create_{fn_name}_exact_at(&mut self, id: {}Id, new_size: usize) -> {}Id {{\n", g.second, g.name)?;
write!(w, " self.m_{fn_name}.m_free_list.set(id.index() as usize); \n")?;
write!(w, " self.m_{fn_name}.m_size = new_size;\n")?;
write!(w, " {}Id::from(id.get_value() as {id_prim_type})\n", g.name)?;
write!(w, " }}\n")?;
} else {
write!(w, " {clippy} pub fn create_{fn_name}(&mut self) -> {}Id {{\n", g.name)?;
if g.erasable && !g.relation {
write!(w, " self.m_{fn_name}.m_free_list.set(self.m_{fn_name}.m_size); \n")?;
}
write!(w, " self.m_{fn_name}.m_size += 1; \n")?;
write!(w, " assert!(self.m_{fn_name}.m_size < {}, \"exceeded number of allowed {} (max is {})\");\n", g.size, g.name, g.size)?;
write!(w, " let id = {}Id::from(self.{fn_name}_size() as {id_prim_type});\n", g.name)?;
for og in &root.groups {
let rel_fn_name = Self::to_func_name(og.name.as_str());
if og.relation && og.second == g.name {
if g.erasable {
write!(w, " self.create_{rel_fn_name}_exact_at(id, self.m_{fn_name}.m_size);\n")?;
} else {
write!(w, " self.create_{rel_fn_name}();\n")?;
}
}
}
write!(w, " id\n")?;
write!(w, " }}\n")?;
}
if g.erasable {
if g.relation {
write!(w, " {clippy} pub fn delete_{fn_name}(&mut self, id: {}Id) {{\n", g.second)?;
write!(w, " self.m_{fn_name}.m_free_list.clear(id.index() as usize); \n")?;
} else {
write!(w, " {clippy} pub fn delete_{fn_name}(&mut self, id: {}Id) {{\n", g.name)?;
write!(w, " self.m_{fn_name}.m_free_list.clear(id.index() as usize); \n")?;
for og in &root.groups {
let rel_fn_name = Self::to_func_name(og.name.as_str());
if og.relation && og.second == g.name {
write!(w, " self.delete_{rel_fn_name}(id);\n")?;
}
}
}
write!(w, " }}\n")?;
}
write!(w, " {clippy} pub fn {fn_name}_size(&self) -> usize {{\n")?;
write!(w, " self.m_{fn_name}.m_size\n")?;
write!(w, " }}\n")?;
write!(w, " {clippy} pub fn for_each_{fn_name}(&self, mut f: impl FnMut(&Self, {}Id)) {{\n", g.name)?;
write!(w, " for i in 1..(self.{fn_name}_size() + 1) {{\n")?;
write!(w, " f(self, {}Id::from(i as {id_prim_type}));\n", g.name)?;
write!(w, " }}\n")?;
write!(w, " }}\n")?;
write!(w, " {clippy} pub fn for_each_mut_{fn_name}(&mut self, mut f: impl FnMut(&mut Self, {}Id)) {{\n", g.name)?;
write!(w, " for i in 1..(self.{fn_name}_size() + 1) {{\n")?;
write!(w, " f(self, {}Id::from(i as {id_prim_type}));\n", g.name)?;
write!(w, " }}\n")?;
write!(w, " }}\n")?;
write!(w, " {clippy} pub fn parallel_for_each_{fn_name}(&self, mut f: impl Fn(&Self, {}Id) + Sync + Send) {{\n", g.name)?;
write!(w, " (1..(self.{fn_name}_size() + 1)).into_par_iter()\n")?;
write!(w, " .for_each(|x| f(self, {}Id::from(x as {id_prim_type})));\n", g.name)?;
write!(w, " }}\n")?;
write!(w, " {clippy} pub fn vector_serial_for_each_{fn_name}(&self, mut f: impl FnMut(&Self, viffy::ContigousIntegerVector)) {{\n")?;
write!(w, " let sz = self.{fn_name}_size();\n")?;
write!(w, " let (d, r) = (sz / viffy::VECTOR_SIZE, sz % viffy::VECTOR_SIZE);\n")?;
write!(w, " for i in 0..(d + [0, 1][(r > 0) as usize]) {{\n")?;
write!(w, " let mut v = viffy::ContigousIntegerVector::default();\n")?;
write!(w, " for j in 0..viffy::VECTOR_SIZE {{\n")?;
write!(w, " v = v.set((i * 4 + j + 1) as i32, j);\n")?;
write!(w, " }}\n")?;
write!(w, " f(self, v);\n")?;
write!(w, " }}\n")?;
write!(w, " }}\n")?;
write!(w, " {clippy} pub fn vector_parallel_for_each_{fn_name}(&self, mut f: impl FnMut(&Self, viffy::IntegerVector)) {{\n")?;
write!(w, " for i in 1..(self.{fn_name}_size() + 1) {{\n")?;
write!(w, " f(self, {}Id::from(i as {id_prim_type}).get_value().into_vector());\n", g.name)?;
write!(w, " }}\n")?;
write!(w, " }}\n")?;
write!(w, " {clippy} pub fn iter_{fn_name}(&self) -> impl Iterator<Item = {}Id> {{\n", g.name)?;
write!(w, " (1..(self.{fn_name}_size() + 1)).into_iter().map(|x| {}Id::from(x as {id_prim_type}))\n", g.name)?;
write!(w, " }}\n")?;
write!(w, " {clippy} pub fn parallel_iter_{fn_name}(&self) -> impl ParallelIterator<Item = {}Id> {{\n", g.name)?;
write!(w, " (1..(self.{fn_name}_size() + 1)).into_par_iter().map(|x| {}Id::from(x as {id_prim_type}))\n", g.name)?;
write!(w, " }}\n")?;
}
for og in &root.groups {
let rel_fn_name = Self::to_func_name(og.name.as_str());
if og.adjacency && og.adj_type == g.name {
write!(w, " {clippy} pub fn set_{rel_fn_name}_for_{fn_name}(&mut self, id: {}Id, v: {}Id) {{\n", g.name, g.name)?;
write!(w, " let index = linear_matrix_index({}, id.get_value() as usize, v.get_value() as usize);\n", g.size)?;
write!(w, " let boffs = index / 32;\n")?;
write!(w, " self.m_{fn_name}.m_{rel_fn_name}[boffs] |= 1 << (index % 32);\n")?;
write!(w, " }}\n")?;
write!(w, " {clippy} pub fn clear_{rel_fn_name}_for_{fn_name}(&mut self, id: {}Id, v: {}Id) {{\n", g.name, g.name)?;
write!(w, " let index = linear_matrix_index({}, id.get_value() as usize, v.get_value() as usize);\n", g.size)?;
write!(w, " let boffs = index / 32;\n")?;
write!(w, " self.m_{fn_name}.m_{rel_fn_name}[boffs] &= !(1 << (index % 32));\n")?;
write!(w, " }}\n")?;
write!(w, " {clippy} pub fn get_{rel_fn_name}_for_{fn_name}(&self, id: {}Id, v: {}Id) -> bool {{\n", g.name, g.name)?;
write!(w, " let index = linear_matrix_index({}, id.get_value() as usize, v.get_value() as usize);\n", g.size)?;
write!(w, " let boffs = index / 32;\n")?;
write!(w, " self.m_{fn_name}.m_{rel_fn_name}[boffs] & (1 << (index % 32)) != 0\n")?;
write!(w, " }}\n")?;
write!(w, " {clippy} pub fn for_each_{rel_fn_name}_in_{fn_name}<F: FnMut(&Self, {}Id)>(&self, id: {}Id, mut f: F) {{\n", g.name, g.name)?;
write!(w, " for i in 0..self.{fn_name}_size() {{\n")?;
write!(w, " let index = linear_matrix_index({}, id.get_value() as usize, i);\n", g.size)?;
write!(w, " let boffs = index / 32;\n")?;
write!(w, " let bmask = 1 << (index % 32);\n")?;
write!(w, " if i != id.get_value() as usize {{ if self.m_{fn_name}.m_{rel_fn_name}[boffs] & bmask != 0 {{ f(self, {}Id::from((i + 1) as {id_prim_type})) }} }}\n", g.name)?;
write!(w, " }}\n")?;
write!(w, " }}\n")?;
write!(w, " {clippy} pub fn for_each_mut_{rel_fn_name}_in_{fn_name}<F: FnMut(&mut Self, {}Id)>(&mut self, id: {}Id, mut f: F) {{\n", g.name, g.name)?;
write!(w, " for i in 0..self.{fn_name}_size() {{\n")?;
write!(w, " let index = linear_matrix_index({}, id.get_value() as usize, i);\n", g.size)?;
write!(w, " let boffs = index / 32;\n")?;
write!(w, " let bmask = 1 << (index % 32);\n")?;
write!(w, " if i != id.get_value() as usize {{ if self.m_{fn_name}.m_{rel_fn_name}[boffs] & bmask != 0 {{ f(self, {}Id::from((i + 1) as {id_prim_type})) }} }}\n", g.name)?;
write!(w, " }}\n")?;
write!(w, " }}\n")?;
} else if og.relation && og.first == g.name {
write!(w, " {clippy} pub fn for_each_{rel_fn_name}_in_{fn_name}<F: FnMut(&Self, {}Id)>(&self, id: {}Id, mut f: F) {{\n", og.second, og.first)?;
write!(w, " for i in self.m_{fn_name}.m_{rel_fn_name}[id.get_value() as usize].iter() {{\n")?;
write!(w, " f(self, {}Id::from(i.get_value()));\n", og.second)?;
write!(w, " }}\n")?;
write!(w, " }}\n")?;
} else if og.relation && og.second == g.name {
write!(w, " {clippy} pub fn get_{rel_fn_name}_{}(&self, id: {}Id) -> {}Id {{\n", og.second_name, og.name, og.second)?;
write!(w, " {}Id::from(id.get_value())\n", og.second)?;
write!(w, " }}\n")?;
write!(w, " {clippy} pub fn get_{}_{rel_fn_name}(&self, id: {}Id) -> {}Id {{\n", og.second_name, og.second, og.name)?;
write!(w, " {}Id::from(id.get_value())\n", og.name)?;
write!(w, " }}\n")?;
write!(w, " {clippy} pub fn get_{fn_name}_{}_from_{rel_fn_name}(&self, id: {}Id) -> {}Id {{\n", og.first_name, g.name, og.first)?;
write!(w, " self.m_{rel_fn_name}.m_{}[id.get_value() as usize]\n", og.first_name)?;
write!(w, " }}\n")?;
if Self::mt_safe() {
write!(w, " {clippy} pub fn set_{fn_name}_{}_from_{rel_fn_name}(&mut self, id: {}Id, value: {}Id) {{\n", og.first_name, g.name, og.first)?;
write!(w, " let rel_id = {}Id::from(id.get_value());\n", og.name)?;
write!(w, " let r = self.m_{rel_fn_name}.m_{}[rel_id.get_value() as usize];\n", og.first_name)?;
write!(w, " if r.is_valid() {{ /*delink old*/\n")?;
write!(w, " let pos = self.m_{}.m_{rel_fn_name}[r.get_value() as usize].iter().position(|&x| x == rel_id);\n", Self::to_func_name(og.first.as_str()))?;
write!(w, " self.m_{}.m_{rel_fn_name}[r.get_value() as usize].remove(pos.unwrap());\n", Self::to_func_name(og.first.as_str()))?;
write!(w, " }}\n")?;
write!(w, " self.m_{rel_fn_name}.m_{}[rel_id.get_value() as usize] = value;\n", og.first_name)?;
write!(w, " self.m_{}.m_{rel_fn_name}[\n", Self::to_func_name(og.first.as_str()))?;
write!(w, " self.m_{rel_fn_name}.m_{}[rel_id.get_value() as usize].get_value() as usize].push(rel_id);\n", og.first_name)?;
write!(w, " }}\n")?;
write!(w, " {clippy} pub fn set_mut_{fn_name}_{}_from_{rel_fn_name}(&mut self, id: {}Id, value: {}Id) {{\n", og.first_name, g.name, og.first)?;
write!(w, " let rel_id = {}Id::from(id.get_value());\n", og.name)?;
write!(w, " let r = self.m_{rel_fn_name}.m_{}[rel_id.get_value() as usize];\n", og.first_name)?;
write!(w, " if r.is_valid() {{ /*delink old*/\n")?;
write!(w, " let pos = self.m_{}.m_{}[r.get_value() as usize].iter().position(|&x| x == rel_id);\n", Self::to_func_name(og.first.as_str()), rel_fn_name)?;
write!(w, " self.m_{}.m_{}[r.get_value() as usize].remove(pos.unwrap());\n", Self::to_func_name(og.first.as_str()), rel_fn_name)?;
write!(w, " }}\n")?;
write!(w, " self.m_{rel_fn_name}.m_{}[rel_id.get_value() as usize] = value;\n", og.first_name)?;
write!(w, " self.m_{}.m_{rel_fn_name}[\n", Self::to_func_name(og.first.as_str()))?;
write!(w, " self.m_{rel_fn_name}.m_{}[rel_id.get_value() as usize].get_value() as usize].push(rel_id);\n", og.first_name)?;
write!(w, " }}\n")?;
} else {
write!(w, " {clippy} pub fn set_{}_{}_from_{}(&mut self, id: {}Id, value: {}Id) {{\n", fn_name, og.first_name, rel_fn_name, g.name, og.first)?;
write!(w, " let rel_id = {}Id::from(id.get_value());\n", og.name)?;
write!(w, " let r = &mut self.m_{}.m_{}[rel_id.get_value() as usize];\n", rel_fn_name, og.first_name)?;
write!(w, " if r.is_valid() {{ /*delink old*/\n")?;
write!(w, " let pos = self.m_{}.m_{}[r.get_value() as usize].iter().position(|&x| x == rel_id);\n", Self::to_func_name(og.first.as_str()), rel_fn_name)?;
write!(w, " self.m_{}.m_{}[r.get_value() as usize].remove(pos.unwrap());\n", Self::to_func_name(og.first.as_str()), rel_fn_name)?;
write!(w, " }}\n")?;
write!(w, " *r = value;\n")?;
write!(w, " self.m_{}.m_{}[r.get_value() as usize].push(rel_id);\n", Self::to_func_name(og.first.as_str()), rel_fn_name)?;
write!(w, " }}\n")?;
}
}
}
for p in &g.properties {
let ss_index = !(g.unilateral || g.bilateral) as usize;
let id_trans = ["&id", "id.get_value() as usize"][ss_index];
let nb_setter = [
".insert(id, *v)",
"[id.get_value() as usize] = *v"
][ss_index];
let nb_getter = [
".get(&id).map(|x| *x).unwrap_or_default()",
"[id.get_value() as usize]"
][ss_index];
if p.borrow_only {
write!(w, " {clippy} pub fn get_{fn_name}_{}(&self, id: {}Id) -> &{} {{\n", p.name, g.name, p.value)?;
if g.size > 0 { write!(w, " unsafe {{ std::hint::assert_unchecked(id.get_value() < {}); }}\n", g.size)?; }
write!(w, " &self.m_{fn_name}.m_{}[{id_trans}]\n", p.name)?;
write!(w, " }}\n")?;
write!(w, " {clippy} pub fn get_mut_{fn_name}_{}(&mut self, id: {}Id) -> &mut {} {{\n", p.name, g.name, p.value)?;
if g.size > 0 { write!(w, " unsafe {{ std::hint::assert_unchecked(id.get_value() < {}); }}\n", g.size)?; }
write!(w, " &mut self.m_{fn_name}.m_{}[{id_trans}]\n", p.name)?;
write!(w, " }}\n")?;
write!(w, " {clippy} pub fn set_{fn_name}_{}(&mut self, id: {}Id, v: &{}) {{\n", p.name, g.name, p.value)?;
if g.size > 0 { write!(w, " unsafe {{ std::hint::assert_unchecked(id.get_value() < {}); }}\n", g.size)?; }
write!(w, " self.m_{fn_name}.m_{}[{id_trans}].clone_from(v);\n", p.name)?;
write!(w, " }}\n")?;
} else {
write!(w, " {clippy} pub fn get_{fn_name}_{}(&self, id: {}Id) -> {} {{\n", p.name, g.name, p.value)?;
if g.size > 0 { write!(w, " unsafe {{ std::hint::assert_unchecked(id.get_value() < {}); }}\n", g.size)?; }
write!(w, " self.m_{fn_name}.m_{}{nb_getter}\n", p.name)?;
write!(w, " }}\n")?;
write!(w, " {clippy} pub fn set_{fn_name}_{}(&mut self, id: {}Id, v: &{}) {{\n", p.name, g.name, p.value)?;
if g.size > 0 { write!(w, " unsafe {{ std::hint::assert_unchecked(id.get_value() < {}); }}\n", g.size)?; }
write!(w, " self.m_{fn_name}.m_{}{nb_setter};\n", p.name)?;
write!(w, " }}\n")?;
}
}
}
write!(w, "}}")?;
Ok(())
}
}
pub fn write_file<P>(
input: P,
output: P
) -> Result<(), Box<dyn std::error::Error>>
where
P: AsRef<std::path::Path> + std::fmt::Display + Copy
{
let s = std::fs::read_to_string(input).unwrap();
let mut parser = State::from_str(s.as_str());
let mut w = Vec::new();
let res = parser.do_parse();
State::print_root(&mut w, &res)?;
let out_dir = std::env::var_os("OUT_DIR").unwrap();
let dest_path = std::path::Path::new(&out_dir).join(output);
std::fs::write(&dest_path, w).unwrap();
Ok(())
}