enh(generic-snmp): new ast object

This commit is contained in:
David Boucher 2025-04-18 15:00:42 +02:00
parent 1ecfbb7d11
commit ef7dffae3d
7 changed files with 395 additions and 80 deletions

View File

@ -0,0 +1,267 @@
use snmp::{SnmpItem, SnmpResult};
use std::str;
#[derive(Debug)]
pub enum Expr<'input> {
Id(&'input [u8]),
Number(f64),
OpPlus(Box<Expr<'input>>, Box<Expr<'input>>),
OpMinus(Box<Expr<'input>>, Box<Expr<'input>>),
OpStar(Box<Expr<'input>>, Box<Expr<'input>>),
OpSlash(Box<Expr<'input>>, Box<Expr<'input>>),
Fn(Func, Box<Expr<'input>>),
}
#[derive(Debug)]
pub enum Func {
Average,
Min,
Max,
}
#[derive(Debug)]
pub enum ExprResult {
Vector(Vec<f64>),
Scalar(f64),
}
impl std::ops::Add for ExprResult {
type Output = ExprResult;
fn add(self, other: Self) -> Self::Output {
match (self, other) {
(ExprResult::Scalar(a), ExprResult::Scalar(b)) => ExprResult::Scalar(a + b),
(ExprResult::Vector(a), ExprResult::Vector(b)) => {
let len_a = a.len();
let len_b = b.len();
if len_a == len_b {
let mut result = Vec::with_capacity(len_a);
for i in 0..len_a {
result.push(a[i] + b[i]);
}
ExprResult::Vector(result)
} else {
if len_a > len_b {
let mut result = a.clone();
for (idx, value) in b.iter().enumerate() {
result[idx] += value;
}
ExprResult::Vector(result)
} else {
let mut result = b.clone();
for (idx, value) in a.iter().enumerate() {
result[idx] += value;
}
ExprResult::Vector(result)
}
}
}
(ExprResult::Scalar(a), ExprResult::Vector(b)) => {
let mut result = b.clone();
for value in result.iter_mut() {
*value += a;
}
ExprResult::Vector(result)
}
(ExprResult::Vector(a), ExprResult::Scalar(b)) => {
let mut result = a.clone();
for value in result.iter_mut() {
*value += b;
}
ExprResult::Vector(result)
}
}
}
}
impl std::ops::Sub for ExprResult {
type Output = ExprResult;
fn sub(self, other: Self) -> Self::Output {
match (self, other) {
(ExprResult::Scalar(a), ExprResult::Scalar(b)) => ExprResult::Scalar(a - b),
(ExprResult::Vector(a), ExprResult::Vector(b)) => {
let len_a = a.len();
let len_b = b.len();
if len_a == len_b {
let mut result = Vec::with_capacity(len_a);
for i in 0..len_a {
result.push(a[i] - b[i]);
}
ExprResult::Vector(result)
} else {
if len_a > len_b {
let mut result = a.clone();
for (idx, value) in b.iter().enumerate() {
result[idx] -= value;
}
ExprResult::Vector(result)
} else {
let mut result = b.clone();
for (idx, value) in a.iter().enumerate() {
result[idx] -= value;
}
ExprResult::Vector(result)
}
}
}
(ExprResult::Scalar(a), ExprResult::Vector(b)) => {
let mut result = vec![0_f64; b.len()];
for (idx, value) in result.iter_mut().enumerate() {
*value = a - b[idx];
}
ExprResult::Vector(result)
}
(ExprResult::Vector(a), ExprResult::Scalar(b)) => {
let mut result = a.clone();
for value in result.iter_mut() {
*value -= b;
}
ExprResult::Vector(result)
}
}
}
}
impl std::ops::Mul for ExprResult {
type Output = ExprResult;
fn mul(self, other: Self) -> Self::Output {
match (self, other) {
(ExprResult::Scalar(a), ExprResult::Scalar(b)) => ExprResult::Scalar(a * b),
(ExprResult::Vector(a), ExprResult::Vector(b)) => {
let len_a = a.len();
let len_b = b.len();
if len_a == len_b {
let mut result = Vec::with_capacity(len_a);
for i in 0..len_a {
result.push(a[i] * b[i]);
}
ExprResult::Vector(result)
} else {
if len_a > len_b {
let mut result = a.clone();
for (idx, value) in b.iter().enumerate() {
result[idx] *= value;
}
ExprResult::Vector(result)
} else {
let mut result = b.clone();
for (idx, value) in a.iter().enumerate() {
result[idx] *= value;
}
ExprResult::Vector(result)
}
}
}
(ExprResult::Scalar(a), ExprResult::Vector(b)) => {
let mut result = b.clone();
for value in result.iter_mut() {
*value *= a;
}
ExprResult::Vector(result)
}
(ExprResult::Vector(a), ExprResult::Scalar(b)) => {
let mut result = a.clone();
for value in result.iter_mut() {
*value *= b;
}
ExprResult::Vector(result)
}
}
}
}
impl std::ops::Div for ExprResult {
type Output = ExprResult;
fn div(self, other: Self) -> Self::Output {
match (self, other) {
(ExprResult::Scalar(a), ExprResult::Scalar(b)) => ExprResult::Scalar(a / b),
(ExprResult::Vector(a), ExprResult::Vector(b)) => {
let len_a = a.len();
let len_b = b.len();
if len_a == len_b {
let mut result = Vec::with_capacity(len_a);
for i in 0..len_a {
result.push(a[i] / b[i]);
}
ExprResult::Vector(result)
} else {
if len_a > len_b {
let mut result = a.clone();
for (idx, value) in b.iter().enumerate() {
result[idx] /= value;
}
ExprResult::Vector(result)
} else {
let mut result = b.clone();
for (idx, value) in a.iter().enumerate() {
result[idx] /= value;
}
ExprResult::Vector(result)
}
}
}
(ExprResult::Scalar(a), ExprResult::Vector(b)) => {
let mut result = vec![0_f64; b.len()];
for (idx, value) in result.iter_mut().enumerate() {
*value = a / b[idx];
}
ExprResult::Vector(result)
}
(ExprResult::Vector(a), ExprResult::Scalar(b)) => {
let mut result = a.clone();
for value in result.iter_mut() {
*value /= b;
}
ExprResult::Vector(result)
}
}
}
}
impl<'input> Expr<'input> {
pub fn eval(&self, collect: &Vec<SnmpResult>) -> ExprResult {
match self {
Expr::Number(n) => ExprResult::Scalar(*n),
Expr::Id(key) => {
for result in collect {
let k = str::from_utf8(key).unwrap();
let item = &result.items[k];
match item {
SnmpItem::Nbr(n) => {
if n.len() == 1 {
return ExprResult::Scalar(n[0]);
} else {
return ExprResult::Vector(n.clone());
}
}
_ => panic!("Should be a number"),
}
}
ExprResult::Scalar(0.0)
}
Expr::OpPlus(left, right) => left.eval(collect) + right.eval(collect),
Expr::OpMinus(left, right) => left.eval(collect) - right.eval(collect),
Expr::OpStar(left, right) => left.eval(collect) * right.eval(collect),
Expr::OpSlash(left, right) => left.eval(collect) / right.eval(collect),
Expr::Fn(func, expr) => {
let v = expr.eval(collect);
match func {
Func::Average => v,
Func::Min => v,
Func::Max => v,
}
}
}
}
pub fn eval_as_str(&self) -> &[u8] {
if let Expr::Id(id) = self {
return id;
} else {
return b"Bad value";
}
}
}

View File

@ -4,20 +4,23 @@ use std::str;
pub type Spanned<Tok, Loc, Error> = Result<(Loc, Tok, Loc), Error>; pub type Spanned<Tok, Loc, Error> = Result<(Loc, Tok, Loc), Error>;
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
pub enum Tok { pub enum Tok<'input> {
Num(f32), Num(f64),
Id, Id(&'input [u8]),
OpStar, OpStar,
OpSlash, OpSlash,
OpPlus, OpPlus,
OpMinus, OpMinus,
LParen, LParen,
RParen, RParen,
LBrace,
RBrace,
} }
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub enum LexicalError { pub enum LexicalError {
NotPossible, NotPossible,
UnmatchedBrace,
// Not possible // Not possible
} }
@ -35,8 +38,9 @@ impl<'input> Lexer<'input> {
} }
} }
fn number(&mut self, start: usize, chars: &[u8]) -> Option<Spanned<Tok, usize, LexicalError>> { fn number(&mut self, start: usize) -> Option<Spanned<Tok<'input>, usize, LexicalError>> {
// Consume digits and decimal points // Consume digits and decimal points
let chars = self.chars.as_bytes();
let mut end = start; let mut end = start;
let mut done = false; let mut done = false;
for c in chars[(start + 1)..].iter() { for c in chars[(start + 1)..].iter() {
@ -59,22 +63,19 @@ impl<'input> Lexer<'input> {
self.offset = end; self.offset = end;
let value = str::from_utf8(&chars[start..end]) let value = str::from_utf8(&chars[start..end])
.unwrap_or("Bad value") .unwrap_or("Bad value")
.parse::<f32>() .parse::<f64>()
.unwrap_or(0.0); .unwrap_or(0.0);
Some(Ok((start, Tok::Num(value), end))) Some(Ok((start, Tok::Num(value), end)))
} }
fn identifier( fn identifier(&mut self, start: usize) -> Option<Spanned<Tok<'input>, usize, LexicalError>> {
&mut self,
start: usize,
chars: &[u8],
) -> Option<Spanned<Tok, usize, LexicalError>> {
// Consume identifier // Consume identifier
let chars = self.chars.as_bytes();
let mut end = start; let mut end = start;
let mut done = false; let mut done = false;
for c in chars[(start + 1)..].iter() { for c in chars[(start + 1)..].iter() {
end += 1; end += 1;
if !c.is_ascii_alphanumeric() && *c != b'_' { if !c.is_ascii_alphanumeric() && *c != b'_' && *c != b'.' {
done = true; done = true;
break; break;
} }
@ -89,12 +90,12 @@ impl<'input> Lexer<'input> {
str::from_utf8(&chars[start..end]).unwrap_or("Bad value") str::from_utf8(&chars[start..end]).unwrap_or("Bad value")
); );
self.offset = end; self.offset = end;
Some(Ok((start, Tok::Id, end))) Some(Ok((start, Tok::Id(&chars[start..end]), end)))
} }
} }
impl<'input> Iterator for Lexer<'input> { impl<'input> Iterator for Lexer<'input> {
type Item = Spanned<Tok, usize, LexicalError>; type Item = Spanned<Tok<'input>, usize, LexicalError>;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
for (i, c) in self.chars.as_bytes().iter().enumerate().skip(self.offset) { for (i, c) in self.chars.as_bytes().iter().enumerate().skip(self.offset) {
@ -124,12 +125,20 @@ impl<'input> Iterator for Lexer<'input> {
self.offset = i + 1; self.offset = i + 1;
return Some(Ok((i, Tok::RParen, i + 1))); return Some(Ok((i, Tok::RParen, i + 1)));
} }
b'{' => {
self.offset = i + 1;
return Some(Ok((i, Tok::LBrace, i + 1)));
}
b'}' => {
self.offset = i + 1;
return Some(Ok((i, Tok::RBrace, i + 1)));
}
b'0'..=b'9' => { b'0'..=b'9' => {
// Consume digits and decimal points // Consume digits and decimal points
return self.number(i, &self.chars.as_bytes()); return self.number(i);
} }
b'a'..=b'z' | b'A'..=b'Z' | b'_' => { b'a'..=b'z' | b'A'..=b'Z' | b'_' => {
return self.identifier(i, &self.chars.as_bytes()); return self.identifier(i);
} }
_ => { _ => {
// Unknown character // Unknown character
@ -151,9 +160,9 @@ mod Test {
fn test_lexer_num_id_num() { fn test_lexer_num_id_num() {
let input = "123 abc 456"; let input = "123 abc 456";
let mut lexer = Lexer::new(input); let mut lexer = Lexer::new(input);
assert_eq!(lexer.next(), Some(Ok((0, Tok::Num(123_f32), 3)))); assert_eq!(lexer.next(), Some(Ok((0, Tok::Num(123_f64), 3))));
assert_eq!(lexer.next(), Some(Ok((4, Tok::Id, 7)))); assert_eq!(lexer.next(), Some(Ok((4, Tok::Id(b"abc"), 7))));
assert_eq!(lexer.next(), Some(Ok((8, Tok::Num(456_f32), 11)))); assert_eq!(lexer.next(), Some(Ok((8, Tok::Num(456_f64), 11))));
assert_eq!(lexer.next(), None); assert_eq!(lexer.next(), None);
} }
@ -161,20 +170,20 @@ mod Test {
fn test_lexer_id_num_id() { fn test_lexer_id_num_id() {
let input = "abc 123 def"; let input = "abc 123 def";
let mut lexer = Lexer::new(input); let mut lexer = Lexer::new(input);
assert_eq!(lexer.next(), Some(Ok((0, Tok::Id, 3)))); assert_eq!(lexer.next(), Some(Ok((0, Tok::Id(b"abc"), 3))));
assert_eq!(lexer.next(), Some(Ok((4, Tok::Num(123_f32), 7)))); assert_eq!(lexer.next(), Some(Ok((4, Tok::Num(123_f64), 7))));
assert_eq!(lexer.next(), Some(Ok((8, Tok::Id, 11)))); assert_eq!(lexer.next(), Some(Ok((8, Tok::Id(b"def"), 11))));
} }
#[test] #[test]
fn test_lexer_num_op() { fn test_lexer_num_op() {
let input = "1+2*3"; let input = "1+2*3";
let mut lexer = Lexer::new(input); let mut lexer = Lexer::new(input);
assert_eq!(lexer.next(), Some(Ok((0, Tok::Num(1_f32), 1)))); assert_eq!(lexer.next(), Some(Ok((0, Tok::Num(1_f64), 1))));
assert_eq!(lexer.next(), Some(Ok((1, Tok::OpPlus, 2)))); assert_eq!(lexer.next(), Some(Ok((1, Tok::OpPlus, 2))));
assert_eq!(lexer.next(), Some(Ok((2, Tok::Num(2_f32), 3)))); assert_eq!(lexer.next(), Some(Ok((2, Tok::Num(2_f64), 3))));
assert_eq!(lexer.next(), Some(Ok((3, Tok::OpStar, 4)))); assert_eq!(lexer.next(), Some(Ok((3, Tok::OpStar, 4))));
assert_eq!(lexer.next(), Some(Ok((4, Tok::Num(3_f32), 5)))); assert_eq!(lexer.next(), Some(Ok((4, Tok::Num(3_f64), 5))));
assert_eq!(lexer.next(), None); assert_eq!(lexer.next(), None);
} }
} }

View File

@ -1,6 +1,9 @@
pub mod ast;
pub mod lexer; pub mod lexer;
use lalrpop_util::lalrpop_mod; use self::ast::ExprResult;
use self::lexer::{LexicalError, Tok};
use lalrpop_util::{lalrpop_mod, ParseError};
use serde::Deserialize; use serde::Deserialize;
use snmp::SnmpResult; use snmp::SnmpResult;
@ -10,10 +13,10 @@ lalrpop_mod!(grammar);
pub struct Metric { pub struct Metric {
pub name: String, pub name: String,
pub prefix: Option<String>, pub prefix: Option<String>,
value: String, pub value: String,
uom: Option<String>, uom: Option<String>,
min: Option<f32>, min: Option<f64>,
max: Option<f32>, max: Option<f64>,
} }
#[derive(Deserialize, Debug)] #[derive(Deserialize, Debug)]
@ -35,8 +38,19 @@ impl<'a> Parser<'a> {
} }
} }
pub fn eval(&self, expr: &str) -> f32 { pub fn eval(
2.0_f32 &self,
expr: &'a str,
) -> Result<ExprResult, ParseError<usize, Tok<'a>, LexicalError>> {
let lexer = lexer::Lexer::new(expr);
let res = self.parser.parse(lexer);
match res {
Ok(res) => {
let res = res.eval(self.collect);
Ok(res)
}
Err(e) => Err(e),
}
} }
} }
@ -48,7 +62,7 @@ mod Test {
let lexer = lexer::Lexer::new("123"); let lexer = lexer::Lexer::new("123");
let res = grammar::ExprParser::new().parse(lexer); let res = grammar::ExprParser::new().parse(lexer);
assert!(res.is_ok()); assert!(res.is_ok());
assert!(res.unwrap() == 123_f32); assert!(res.unwrap().eval() == 123_f32);
let lexer = lexer::Lexer::new("123"); let lexer = lexer::Lexer::new("123");
assert!(grammar::ExprParser::new().parse(lexer).is_ok()); assert!(grammar::ExprParser::new().parse(lexer).is_ok());
let lexer = lexer::Lexer::new("(((123))"); let lexer = lexer::Lexer::new("(((123))");
@ -61,27 +75,27 @@ mod Test {
let lexer = lexer::Lexer::new("1 + 2"); let lexer = lexer::Lexer::new("1 + 2");
let res = grammar::ExprParser::new().parse(lexer); let res = grammar::ExprParser::new().parse(lexer);
assert!(res.is_ok()); assert!(res.is_ok());
assert!(res.unwrap() == 3_f32); assert!(res.unwrap().eval() == 3_f32);
let lexer = lexer::Lexer::new("1 + 2 - 3"); let lexer = lexer::Lexer::new("1 + 2 - 3");
let res = grammar::ExprParser::new().parse(lexer); let res = grammar::ExprParser::new().parse(lexer);
assert!(res.is_ok()); assert!(res.is_ok());
assert!(res.unwrap() == 0_f32); assert!(res.unwrap().eval() == 0_f32);
let lexer = lexer::Lexer::new("1 - 2 + 3"); let lexer = lexer::Lexer::new("1 - 2 + 3");
let res = grammar::ExprParser::new().parse(lexer); let res = grammar::ExprParser::new().parse(lexer);
assert!(res.is_ok()); assert!(res.is_ok());
assert!(res.unwrap() == 2_f32); assert!(res.unwrap().eval() == 2_f32);
let lexer = lexer::Lexer::new("1 - (2 + 3)"); let lexer = lexer::Lexer::new("1 - (2 + 3)");
let res = grammar::ExprParser::new().parse(lexer); let res = grammar::ExprParser::new().parse(lexer);
assert!(res.is_ok()); assert!(res.is_ok());
assert!(res.unwrap() == -4_f32); assert!(res.unwrap().eval() == -4_f32);
let lexer = lexer::Lexer::new("1 - (2 + (3 - (4 + (5 - (6 + 7)))))"); let lexer = lexer::Lexer::new("1 - (2 + (3 - (4 + (5 - (6 + 7)))))");
let res = grammar::ExprParser::new().parse(lexer); let res = grammar::ExprParser::new().parse(lexer);
assert!(res.is_ok()); assert!(res.is_ok());
assert!(res.unwrap() == -8_f32); assert!((res.unwrap()).eval() == -8_f32);
} }
#[test] #[test]
@ -89,27 +103,27 @@ mod Test {
let lexer = lexer::Lexer::new("2 * 3"); let lexer = lexer::Lexer::new("2 * 3");
let res = grammar::ExprParser::new().parse(lexer); let res = grammar::ExprParser::new().parse(lexer);
assert!(res.is_ok()); assert!(res.is_ok());
assert!(res.unwrap() == 6_f32); assert!(res.unwrap().eval() == 6_f32);
let lexer = lexer::Lexer::new("1 + 2 * 3"); let lexer = lexer::Lexer::new("1 + 2 * 3");
let res = grammar::ExprParser::new().parse(lexer); let res = grammar::ExprParser::new().parse(lexer);
assert!(res.is_ok()); assert!(res.is_ok());
assert!(res.unwrap() == 7_f32); assert!(res.unwrap().eval() == 7_f32);
let lexer = lexer::Lexer::new("(1 + 2) * 3"); let lexer = lexer::Lexer::new("(1 + 2) * 3");
let res = grammar::ExprParser::new().parse(lexer); let res = grammar::ExprParser::new().parse(lexer);
assert!(res.is_ok()); assert!(res.is_ok());
assert!(res.unwrap() == 9_f32); assert!(res.unwrap().eval() == 9_f32);
let lexer = lexer::Lexer::new("2 * 3 * 4"); let lexer = lexer::Lexer::new("2 * 3 * 4");
let res = grammar::ExprParser::new().parse(lexer); let res = grammar::ExprParser::new().parse(lexer);
assert!(res.is_ok()); assert!(res.is_ok());
assert!(res.unwrap() == 24_f32); assert!(res.unwrap().eval() == 24_f32);
let lexer = lexer::Lexer::new("2 * 3 / 2"); let lexer = lexer::Lexer::new("2 * 3 / 2");
let res = grammar::ExprParser::new().parse(lexer); let res = grammar::ExprParser::new().parse(lexer);
assert!(res.is_ok()); assert!(res.is_ok());
assert!(res.unwrap() == 3_f32); assert!(res.unwrap().eval() == 3_f32);
// We have an issue with 2/0, I know it but we'll fix it later. // We have an issue with 2/0, I know it but we'll fix it later.
} }
@ -119,7 +133,20 @@ mod Test {
let lexer = lexer::Lexer::new("1 + (3 + 2 * 3) / 3"); let lexer = lexer::Lexer::new("1 + (3 + 2 * 3) / 3");
let res = grammar::ExprParser::new().parse(lexer); let res = grammar::ExprParser::new().parse(lexer);
assert!(res.is_ok()); assert!(res.is_ok());
assert!(res.unwrap() == 4_f32); assert!(res.unwrap().eval() == 4_f32);
}
#[test]
fn identifier() {
let lexer = lexer::Lexer::new("{abc} + 1");
let res = grammar::ExprParser::new().parse(lexer);
assert!(res.is_ok());
println!("{:?}", res);
assert!(res.unwrap().eval() == 1_f32);
let lexer = lexer::Lexer::new("abc + 1");
let res = grammar::ExprParser::new().parse(lexer);
assert!(res.is_err());
} }
#[test] #[test]

View File

@ -4,7 +4,7 @@ extern crate serde_json;
use compute::{Compute, Parser}; use compute::{Compute, Parser};
use serde::Deserialize; use serde::Deserialize;
use snmp::{snmp_bulk_get, snmp_bulk_walk, snmp_bulk_walk_with_labels}; use snmp::{snmp_bulk_get, snmp_bulk_walk, snmp_bulk_walk_with_labels};
use std::collections::{BTreeMap, HashMap}; use std::collections::HashMap;
#[derive(Copy, Clone, PartialEq)] #[derive(Copy, Clone, PartialEq)]
pub enum Status { pub enum Status {
@ -56,7 +56,7 @@ pub struct Snmp {
name: String, name: String,
oid: String, oid: String,
query: QueryType, query: QueryType,
labels: Option<BTreeMap<String, String>>, labels: Option<HashMap<String, String>>,
} }
#[derive(Deserialize, Debug)] #[derive(Deserialize, Debug)]
@ -82,7 +82,7 @@ pub struct CommandExt {
pub critical_agregation: Option<String>, pub critical_agregation: Option<String>,
} }
fn compute_status(value: f32, warn: &Option<String>, crit: &Option<String>) -> Status { fn compute_status(value: f64, warn: &Option<String>, crit: &Option<String>) -> Status {
if let Some(c) = crit { if let Some(c) = crit {
let crit = c.parse().unwrap(); let crit = c.parse().unwrap();
if value > crit { if value > crit {
@ -130,12 +130,20 @@ impl Command {
} }
} }
let p = Parser::new(&collect); for (i, metric) in self.compute.metrics.iter().enumerate() {
for (idx, metric) in self.compute.metrics.iter().enumerate() {
let name = match &metric.prefix { let name = match &metric.prefix {
Some(prefix) => format!("{}#{}", p.eval(prefix), metric.name), Some(prefix) => {
None => format!("{}#{}", idx, metric.name), format!("{:?}#{}", prefix, metric.name)
}
None => format!("{}#{}", i, metric.name),
}; };
println!("name: {}", name);
let value = &metric.value;
println!("value: {}", value);
let parser = Parser::new(&collect);
let value = parser.eval(value).unwrap();
println!("value result: {:?}", value);
} }
if !to_get.is_empty() { if !to_get.is_empty() {

View File

@ -1,23 +1,24 @@
use std::str::FromStr;
use compute::lexer; use compute::lexer;
use compute::ast;
grammar; grammar<'input>;
pub Expr: f32 = { pub Expr: Box<ast::Expr<'input>> = {
<s:Expr> "+" <p:Product> => s + p, <s:Expr> "+" <p:Product> => Box::new(ast::Expr::OpPlus(<>)),
<s:Expr> "-" <p:Product> => s - p, <s:Expr> "-" <p:Product> => Box::new(ast::Expr::OpMinus(<>)),
<p:Product> => p, Product,
}; };
pub Product: f32 = { pub Product: Box<ast::Expr<'input>> = {
<s:Product> "*" <v:Term> => s * v, <s:Product> "*" <v:Term> => Box::new(ast::Expr::OpStar(<>)),
<s:Product> "/" <v:Term> => s / v, <s:Product> "/" <v:Term> => Box::new(ast::Expr::OpSlash(<>)),
<v:Term> => v, <v:Term> => <>,
}; };
pub Term: f32 = { pub Term: Box<ast::Expr<'input>> = {
"num" => <>, "num" => Box::new(ast::Expr::Number(<>)),
"(" <v:Expr> ")" => v, "(" <v:Expr> ")" => <>,
"{" <"id"> "}" => Box::new(ast::Expr::Id(<>)),
}; };
extern { extern {
@ -26,13 +27,16 @@ extern {
// ... // ...
enum lexer::Tok { enum lexer::Tok<'input> {
"*" => lexer::Tok::OpStar, "*" => lexer::Tok::OpStar,
"/" => lexer::Tok::OpSlash, "/" => lexer::Tok::OpSlash,
"+" => lexer::Tok::OpPlus, "+" => lexer::Tok::OpPlus,
"-" => lexer::Tok::OpMinus, "-" => lexer::Tok::OpMinus,
"(" => lexer::Tok::LParen, "(" => lexer::Tok::LParen,
")" => lexer::Tok::RParen, ")" => lexer::Tok::RParen,
"num" => lexer::Tok::Num(<f32>) "{" => lexer::Tok::LBrace,
"}" => lexer::Tok::RBrace,
"num" => lexer::Tok::Num(<f64>),
"id" => lexer::Tok::Id(<&'input [u8]>),
} }
} }

View File

@ -12,7 +12,7 @@ mod compute;
mod generic; mod generic;
mod snmp; mod snmp;
use generic::{Command, CommandExt}; use generic::Command;
use lalrpop_util::lalrpop_mod; use lalrpop_util::lalrpop_mod;
use serde_json::Result; use serde_json::Result;
//use snmp::snmp_get; //use snmp::snmp_get;

View File

@ -11,26 +11,26 @@ use rasn_snmp::v2::VarBind;
use rasn_snmp::v2::VarBindValue; use rasn_snmp::v2::VarBindValue;
use rasn_snmp::v2::{GetBulkRequest, GetNextRequest, GetRequest}; use rasn_snmp::v2::{GetBulkRequest, GetNextRequest, GetRequest};
use rasn_snmp::v2c::Message; use rasn_snmp::v2c::Message;
use std::collections::BTreeMap; use std::collections::HashMap;
use std::convert::TryInto; use std::convert::TryInto;
use std::net::UdpSocket; use std::net::UdpSocket;
pub enum ValueType { pub enum ValueType {
None(()), None(()),
Integer(i64), Integer(i64),
Float(f32), Float(f64),
String(String), String(String),
} }
#[derive(Debug)] #[derive(Debug)]
pub enum SnmpItem { pub enum SnmpItem {
Nbr(Vec<f32>), Nbr(Vec<f64>),
Str(Vec<String>), Str(Vec<String>),
} }
#[derive(Debug)] #[derive(Debug)]
pub struct SnmpResult { pub struct SnmpResult {
items: BTreeMap<String, SnmpItem>, pub items: HashMap<String, SnmpItem>,
last_oid: Vec<u32>, last_oid: Vec<u32>,
} }
@ -179,7 +179,7 @@ pub fn snmp_bulk_get<'a>(
.collect::<Vec<Vec<u32>>>(); .collect::<Vec<Vec<u32>>>();
let mut retval = SnmpResult { let mut retval = SnmpResult {
items: BTreeMap::new(), items: HashMap::new(),
last_oid: Vec::new(), last_oid: Vec::new(),
}; };
let mut request_id: i32 = 1; let mut request_id: i32 = 1;
@ -256,7 +256,7 @@ pub fn snmp_bulk_walk<'a>(
.collect::<Vec<u32>>(); .collect::<Vec<u32>>();
let mut oid_tab = &oid_init; let mut oid_tab = &oid_init;
let mut retval = SnmpResult { let mut retval = SnmpResult {
items: BTreeMap::new(), items: HashMap::new(),
last_oid: Vec::new(), last_oid: Vec::new(),
}; };
let request_id: i32 = 1; let request_id: i32 = 1;
@ -314,7 +314,7 @@ pub fn snmp_bulk_walk_with_labels<'a>(
community: &str, community: &str,
oid: &str, oid: &str,
snmp_name: &str, snmp_name: &str,
labels: &'a BTreeMap<String, String>, labels: &'a HashMap<String, String>,
) -> SnmpResult { ) -> SnmpResult {
let oid_init = oid let oid_init = oid
.split('.') .split('.')
@ -323,7 +323,7 @@ pub fn snmp_bulk_walk_with_labels<'a>(
let mut oid_tab = &oid_init; let mut oid_tab = &oid_init;
let mut retval = SnmpResult { let mut retval = SnmpResult {
items: BTreeMap::new(), items: HashMap::new(),
last_oid: Vec::new(), last_oid: Vec::new(),
}; };
let request_id: i32 = 1; let request_id: i32 = 1;
@ -380,7 +380,7 @@ impl SnmpResult {
decoded: Message<Pdus>, decoded: Message<Pdus>,
oid: &str, oid: &str,
snmp_name: &str, snmp_name: &str,
labels: &'a BTreeMap<String, String>, labels: &'a HashMap<String, String>,
walk: bool, walk: bool,
) -> bool { ) -> bool {
let mut completed = false; let mut completed = false;
@ -461,7 +461,7 @@ impl SnmpResult {
ValueType::String(_) => { ValueType::String(_) => {
panic!("Value should be a float"); panic!("Value should be a float");
} }
ValueType::Integer(i) => *i as f32, ValueType::Integer(i) => *i as f64,
}), }),
SnmpItem::Str(v) => v.push(match &typ { SnmpItem::Str(v) => v.push(match &typ {
ValueType::Float(_) => { ValueType::Float(_) => {
@ -482,7 +482,7 @@ impl SnmpResult {
panic!("Should not arrive"); panic!("Should not arrive");
} }
ValueType::String(s) => SnmpItem::Str(vec![s]), ValueType::String(s) => SnmpItem::Str(vec![s]),
ValueType::Integer(i) => SnmpItem::Nbr(vec![i as f32]), ValueType::Integer(i) => SnmpItem::Nbr(vec![i as f64]),
}); });
} }
} }
@ -572,7 +572,7 @@ impl SnmpResult {
ValueType::String(_) => { ValueType::String(_) => {
panic!("Value should be a float"); panic!("Value should be a float");
} }
ValueType::Integer(i) => *i as f32, ValueType::Integer(i) => *i as f64,
}), }),
SnmpItem::Str(v) => v.push(match &typ { SnmpItem::Str(v) => v.push(match &typ {
ValueType::Float(_) => { ValueType::Float(_) => {
@ -593,7 +593,7 @@ impl SnmpResult {
panic!("Should not arrive"); panic!("Should not arrive");
} }
ValueType::String(s) => SnmpItem::Str(vec![s]), ValueType::String(s) => SnmpItem::Str(vec![s]),
ValueType::Integer(i) => SnmpItem::Nbr(vec![i as f32]), ValueType::Integer(i) => SnmpItem::Nbr(vec![i as f64]),
}); });
} }
} }
@ -714,7 +714,7 @@ impl SnmpResult {
ValueType::String(_) => { ValueType::String(_) => {
panic!("Value should be a float"); panic!("Value should be a float");
} }
ValueType::Integer(i) => *i as f32, ValueType::Integer(i) => *i as f64,
}), }),
SnmpItem::Str(v) => v.push(match &typ { SnmpItem::Str(v) => v.push(match &typ {
ValueType::Float(_) => { ValueType::Float(_) => {
@ -735,7 +735,7 @@ impl SnmpResult {
panic!("Should not arrive"); panic!("Should not arrive");
} }
ValueType::String(s) => SnmpItem::Str(vec![s]), ValueType::String(s) => SnmpItem::Str(vec![s]),
ValueType::Integer(i) => SnmpItem::Nbr(vec![i as f32]), ValueType::Integer(i) => SnmpItem::Nbr(vec![i as f64]),
}); });
} }
} }