mirror of
https://github.com/speatzle/nfsense.git
synced 2025-05-10 18:38:22 +00:00
implement macro_db
This commit is contained in:
parent
ce5f0b4931
commit
a0c04e3614
2 changed files with 206 additions and 0 deletions
|
@ -7,6 +7,7 @@ use super::object;
|
|||
use super::service;
|
||||
use super::system;
|
||||
use super::vpn;
|
||||
use crate::macro_db;
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Validate, Default, Debug)]
|
||||
pub struct Config {
|
||||
|
@ -18,3 +19,14 @@ pub struct Config {
|
|||
pub vpn: vpn::VPN,
|
||||
pub firewall: firewall::Firewall,
|
||||
}
|
||||
|
||||
macro_db!(
|
||||
{
|
||||
[ S: interface, network::StaticRoute, network.interfaces; network.static_routes ()],
|
||||
[ S: interface, service::DHCPServer, network.interfaces; service.dhcp_servers ()],
|
||||
[ S: interface, service::DNSServer, network.interfaces; service.dns_servers ()],
|
||||
[ S: interface, service::NTPServer, network.interfaces; service.ntp_servers ()],
|
||||
->
|
||||
network::NetworkInterface
|
||||
},
|
||||
);
|
||||
|
|
194
src/definitions/macro_db.rs
Normal file
194
src/definitions/macro_db.rs
Normal file
|
@ -0,0 +1,194 @@
|
|||
/*
|
||||
# TODO
|
||||
thing_referencing is a vec without uniqe names. Should this be a thing? Firwall rules via index? -> Return Both index and name, backreferences are only shown to help users (update ref name might be a backend use but that can just always us the index)
|
||||
validation function (ref exists, no duplicate names, custom functions), register globally/ on config?
|
||||
add function to change name of referenced and update all references
|
||||
|
||||
# Missing link types
|
||||
link_opt -> link from option
|
||||
link_single -> link source parent is not a vec
|
||||
|
||||
link_enum_opt -> link from option in an enum
|
||||
link_enum_multi -> link where source is in an enum and is multiple
|
||||
*/
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
pub struct ReferencedBy {
|
||||
pub name: String,
|
||||
pub path: String,
|
||||
}
|
||||
|
||||
// Main Macro
|
||||
#[macro_export]
|
||||
macro_rules! macro_db {
|
||||
(
|
||||
// all links
|
||||
$(
|
||||
{
|
||||
// link sources
|
||||
$(
|
||||
[ $link_type:tt :
|
||||
$field_name:ident,
|
||||
$thing_referencing:ty,
|
||||
$( $path_referenced:ident ).+;
|
||||
$( $path_referencing:ident ).+
|
||||
( $($arg:tt)* )
|
||||
],
|
||||
)+ ->
|
||||
// link destination
|
||||
$thing_referenced:ty
|
||||
},
|
||||
)+
|
||||
) => {
|
||||
use crate::definitions::macro_db::ReferencedBy;
|
||||
use crate::macro_db_link;
|
||||
// Loop here to impl Relation
|
||||
$(
|
||||
$(
|
||||
macro_db_link!($link_type, $field_name, $thing_referencing, $thing_referenced, $($path_referenced).+ ( $($arg)* ));
|
||||
)+
|
||||
)+
|
||||
|
||||
// Validation here
|
||||
impl Config {
|
||||
#[allow(dead_code)]
|
||||
// TODO make proper error
|
||||
fn validate_relations() -> Result<(), String> {
|
||||
// Loop for each
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// Loop here for back reference, grouped by destination
|
||||
$(
|
||||
impl $thing_referenced {
|
||||
#[allow(dead_code)]
|
||||
fn referenced_by(&self, config: Config) -> Vec<ReferencedBy> {
|
||||
let mut by = Vec::<ReferencedBy>::new();
|
||||
$(
|
||||
macro_rules! macro_db_back_link {
|
||||
(S ()) => {
|
||||
config.$($path_referencing).+.iter().filter(|e| *e.$field_name == self.name).for_each(|e| by.push(ReferencedBy{
|
||||
name: e.name.clone(),
|
||||
path: stringify!(config.$($path_referencing).+).to_string(),
|
||||
}));
|
||||
};
|
||||
(M ()) => {
|
||||
config.$($path_referencing).+.iter().filter(|e| e.$field_name.contains(&self.name)).for_each(|e| by.push(ReferencedBy{
|
||||
name: e.name.clone(),
|
||||
path: stringify!(config.$($path_referencing).+).to_string(),
|
||||
}));
|
||||
};
|
||||
(E
|
||||
($enum_name:ident,
|
||||
$enum_type:ident,
|
||||
$enum_variant:ident,
|
||||
$fn_name:ident )
|
||||
) => {
|
||||
for e in config.$($path_referencing).+.clone() {
|
||||
if let $enum_type::$enum_variant { $field_name, .. } = e.$enum_name {
|
||||
if &self.name == &$field_name {
|
||||
by.push(ReferencedBy{
|
||||
name: e.name.clone(),
|
||||
path: stringify!(config.$($path_referencing).+).to_string(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_db_back_link!($link_type ($($arg)*));
|
||||
)+
|
||||
return by
|
||||
}
|
||||
}
|
||||
)+
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! macro_db_link {
|
||||
( S,
|
||||
$field_name:ident,
|
||||
$thing_referencing:ty,
|
||||
$thing_referenced:ty,
|
||||
$( $path_referenced:ident ).+
|
||||
()
|
||||
) => {
|
||||
impl $thing_referencing {
|
||||
fn $field_name(&self, config: Config) -> $thing_referenced {
|
||||
|
||||
let index = config.$($path_referenced).+.iter().position(|e| *e.name == self.$field_name);
|
||||
|
||||
match index {
|
||||
Some(i) => config.$($path_referenced).+[i].clone(),
|
||||
// This is fine since the config always has to validated before commiting
|
||||
None => panic!("Referenced Thing: '{:?}' does not exist ", self.$field_name),
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
( M,
|
||||
$field_name:ident,
|
||||
$thing_referencing:ty,
|
||||
$thing_referenced:ty,
|
||||
$( $path_referenced:ident ).+
|
||||
()
|
||||
) => {
|
||||
impl $thing_referencing {
|
||||
#[allow(dead_code)]
|
||||
fn $field_name(&self, config: Config) -> Vec<$thing_referenced> {
|
||||
let mut res = Vec::<$thing_referenced>::new();
|
||||
|
||||
for r in self.$field_name.clone() {
|
||||
let index = config.$($path_referenced).+.iter().position(|e| *e.name == r);
|
||||
|
||||
match index {
|
||||
Some(i) => res.push(config.$($path_referenced).+[i].clone()),
|
||||
// This is fine since the config always has to validated before commiting
|
||||
None => panic!("Referenced Thing: '{:?}' does not exist ", self.$field_name),
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
}
|
||||
};
|
||||
( E,
|
||||
$field_name:ident,
|
||||
$thing_referencing:ty,
|
||||
$thing_referenced:ty,
|
||||
$( $path_referenced:ident ).+
|
||||
($enum_name:ident,
|
||||
$enum_type:ident,
|
||||
$enum_variant:ident,
|
||||
$fn_name:ident )
|
||||
) => {
|
||||
// Unfortunetly Enum Variants are not Types, which is why we can't impl on the Variant and need seperate function names (since multiple variant could have the same field name)
|
||||
impl $enum_type {
|
||||
#[allow(dead_code)]
|
||||
fn $fn_name(&self, config: Config) -> $thing_referenced {
|
||||
let index = config.$($path_referenced).+.iter().position(
|
||||
|e| {
|
||||
if let $enum_type::$enum_variant { $field_name, .. } = self.clone() {
|
||||
return *e.name == $field_name;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
);
|
||||
|
||||
match index {
|
||||
Some(i) => config.$($path_referenced).+[i].clone(),
|
||||
// This is fine since the config always has to validated before commiting
|
||||
None => panic!("Referenced Thing: does not exist (from Enum)"),
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
Loading…
Add table
Reference in a new issue