use crate::libapi::FuncDef;
use crate::sym::Symbol;
use crate::lex::{TokType, Token};
use crate::err::Error;
use crate::err::Error::{NameError, TypeError, ParseError};
use crate::str::Buf;
use crate::object::{Obj, ObjRef};
use crate::traits::Dispatchable;
use pkt::Packet;
use std::net::{Ipv4Addr, SocketAddrV4};
use std::rc::Rc;
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum ValType {
Void,
Bool,
U8,
U16,
U32,
U64,
Ip4,
Sock4,
Str,
Type,
Obj,
Func,
Method,
Pkt,
PktGen,
}
pub trait Typed {
fn val_type(&self) -> ValType;
fn is_type(&self, typ: ValType) -> bool {
self.val_type() == typ
}
fn is_nil(&self) -> bool {
self.is_type(ValType::Void)
}
fn is_str(&self) -> bool {
self.is_type(ValType::Str)
}
fn is_integral(&self) -> bool {
matches!(self.val_type(),
| ValType::Bool
| ValType::U8
| ValType::U16
| ValType::U32
| ValType::U64
)
}
fn type_matches<T: Typed>(&self, other: &T) -> bool {
self.is_type(other.val_type())
}
fn is_string_coercible(&self) -> bool {
matches!(self.val_type(),
ValType::Str
| ValType::U8
| ValType::U16
| ValType::U32
| ValType::U64
| ValType::Ip4
)
}
fn compatible_with<T: Typed>(&self, other: &T) -> bool {
self.type_matches(other)
|| self.is_integral() && other.is_integral()
|| (self.is_str() && other.is_string_coercible())
}
}
impl Typed for ValType {
fn val_type(&self) -> ValType {
*self
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum ValDef {
Nil,
Bool(bool),
U8(u8),
U16(u16),
U32(u32),
U64(u64),
Ip4(Ipv4Addr),
Sock4(SocketAddrV4),
Str(&'static [u8]),
Type(ValType),
}
impl ValDef {
pub fn arg_compatible<T: Typed>(&self, other: &T) -> bool {
match self {
ValDef::Type(t) => other.is_nil() || t.compatible_with(other),
_ => self.compatible_with(other),
}
}
}
impl Typed for ValDef {
fn val_type(&self) -> ValType {
use ValType::*;
match self {
ValDef::Nil => Void,
ValDef::Bool(..) => Bool,
ValDef::U8(..) => U8,
ValDef::U16(..) => U16,
ValDef::U32(..) => U32,
ValDef::U64(..) => U64,
ValDef::Ip4(..) => Ip4,
ValDef::Sock4(..) => Sock4,
ValDef::Str(..) => Str,
ValDef::Type(..) => Type,
}
}
}
impl From<Ipv4Addr> for ValDef {
fn from(val: Ipv4Addr) -> Self {
Self::Ip4(val)
}
}
impl From<SocketAddrV4> for ValDef {
fn from(val: SocketAddrV4) -> Self {
Self::Sock4(val)
}
}
impl From<bool> for ValDef {
fn from(val: bool) -> Self {
Self::Bool(val)
}
}
impl From<u64> for ValDef {
fn from(val: u64) -> Self {
Self::U64(val)
}
}
impl<T> From<&'static T> for ValDef where T: AsRef<[u8]> + ? Sized {
fn from(s: &'static T) -> Self {
Self::Str(s.as_ref())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Val {
Nil,
Bool(bool),
U8(u8),
U16(u16),
U32(u32),
U64(u64),
Ip4(Ipv4Addr),
Sock4(SocketAddrV4),
Str(Buf),
Obj(ObjRef),
Func(&'static FuncDef),
Method(ObjRef, &'static FuncDef),
Pkt(Rc<Packet>),
PktGen(Rc<Vec<Packet>>),
}
impl Default for Val {
fn default() -> Self {
Val::Nil
}
}
impl From<ValDef> for Val {
fn from(valdef: ValDef) -> Self {
use ValDef::*;
match valdef {
Nil => Val::Nil,
Bool(b) => Val::Bool(b),
U8(uint) => Val::U8(uint),
U16(uint) => Val::U16(uint),
U32(uint) => Val::U32(uint),
U64(uint) => Val::U64(uint),
Ip4(ip) => Val::Ip4(ip),
Sock4(sock) => Val::Sock4(sock),
Str(s) => Val::Str(Buf::from(s)),
Type(_) => Val::Nil,
}
}
}
impl From<&'static FuncDef> for Val {
fn from(fndef: &'static FuncDef) -> Self {
Val::Func(fndef)
}
}
impl From<SocketAddrV4> for Val {
fn from(sock: SocketAddrV4) -> Self {
Val::Sock4(sock)
}
}
impl From<bool> for Val {
fn from(v: bool) -> Self {
Val::Bool(v)
}
}
impl From<u64> for Val {
fn from(v: u64) -> Self {
Val::U64(v)
}
}
impl From<u32> for Val {
fn from(v: u32) -> Self {
Val::U64(v as u64)
}
}
impl From<u16> for Val {
fn from(v: u16) -> Self {
Val::U64(v as u64)
}
}
impl From<u8> for Val {
fn from(v: u8) -> Self {
Val::U64(v as u64)
}
}
impl From<Val> for bool {
fn from(v: Val) -> Self {
match v {
Val::Bool(b) => b,
Val::U8(u) => u != 0,
Val::U16(u) => u != 0,
Val::U32(u) => u != 0,
Val::U64(u) => u != 0,
_ => unreachable!()
}
}
}
impl From<Val> for u64 {
fn from(v: Val) -> Self {
match v {
Val::U8(u) => u as u64,
Val::U16(u) => u as u64,
Val::U32(u) => u as u64,
Val::U64(u) => u as u64,
_ => unreachable!()
}
}
}
impl From<Val> for u32 {
fn from(v: Val) -> Self {
match v {
Val::U8(u) => u as u32,
Val::U16(u) => u as u32,
Val::U32(u) => u as u32,
Val::U64(u) => u as u32,
_ => unreachable!()
}
}
}
impl From<Val> for u16 {
fn from(v: Val) -> Self {
match v {
Val::U8(u) => u as u16,
Val::U16(u) => u as u16,
Val::U32(u) => u as u16,
Val::U64(u) => u as u16,
_ => unreachable!()
}
}
}
impl From<Val> for u8 {
fn from(v: Val) -> Self {
match v {
Val::U8(u) => u as u8,
Val::U16(u) => u as u8,
Val::U32(u) => u as u8,
Val::U64(u) => u as u8,
_ => unreachable!()
}
}
}
impl From<Val> for SocketAddrV4 {
fn from(v: Val) -> Self {
match v {
Val::Sock4(s) => s,
_ => unreachable!()
}
}
}
impl From<Val> for Ipv4Addr {
fn from(v: Val) -> Self {
match v {
Val::Ip4(a) => a,
_ => unreachable!()
}
}
}
impl From<Val> for Buf {
fn from(v: Val) -> Self {
match v {
Val::Str(s) => s,
Val::U8(u) => Buf::from(&u.to_be_bytes()),
Val::U16(u) => Buf::from(&u.to_be_bytes()),
Val::U32(u) => Buf::from(&u.to_be_bytes()),
Val::U64(u) => Buf::from(&u.to_be_bytes()),
Val::Ip4(ip) => Buf::from(&u32::from(ip).to_be_bytes()),
_ => unreachable!()
}
}
}
impl From<Val> for Rc<Vec<Packet>> {
fn from(v: Val) -> Self {
match v {
Val::PktGen(g) => g,
_ => unreachable!()
}
}
}
impl From<Val> for Rc<Packet> {
fn from(v: Val) -> Self {
match v {
Val::Pkt(p) => p,
_ => unreachable!()
}
}
}
impl From<Val> for Option<Ipv4Addr> {
fn from(v: Val) -> Self {
match v {
Val::Nil => None,
Val::Ip4(ip) => Some(ip),
_ => unreachable!()
}
}
}
impl From<Val> for Option<u64> {
fn from(v: Val) -> Self {
match v {
Val::Nil => None,
_ => Some(u64::from(v)),
}
}
}
impl From<Val> for Option<u32> {
fn from(v: Val) -> Self {
match v {
Val::Nil => None,
_ => Some(u32::from(v)),
}
}
}
impl From<Val> for Option<u16> {
fn from(v: Val) -> Self {
match v {
Val::Nil => None,
_ => Some(u16::from(v)),
}
}
}
impl From<Val> for Option<u8> {
fn from(v: Val) -> Self {
match v {
Val::Nil => None,
_ => Some(u8::from(v)),
}
}
}
impl From<Val> for Option<Buf> {
fn from(v: Val) -> Self {
match v {
Val::Nil => None,
Val::Str(s) => Some(s),
_ => unreachable!()
}
}
}
impl<T: 'static + Obj> From<T> for Val {
fn from(obj: T) -> Self {
Val::Obj(ObjRef::from(obj))
}
}
impl AsRef<[u8]> for Val {
fn as_ref(&self) -> &[u8] {
match self {
Val::Str(s) => s.as_ref(),
_ => unreachable!()
}
}
}
impl Typed for Val {
fn val_type(&self) -> ValType {
use ValType::*;
match self {
Val::Nil => Void,
Val::Bool(..) => Bool,
Val::U8(..) => U8,
Val::U16(..) => U16,
Val::U32(..) => U32,
Val::U64(..) => U64,
Val::Ip4(..) => Ip4,
Val::Sock4(..) => Sock4,
Val::Str(..) => Str,
Val::Obj(..) => Obj,
Val::Func(..) => Func,
Val::Method(..) => Method,
Val::Pkt(..) => Pkt,
Val::PktGen(..) => PktGen,
}
}
}
impl Val {
pub fn from_token(tok: &Token) -> Result<Self, Error> {
use Val::*;
use TokType::*;
let v = tok.val();
match tok.tok_type() {
StringLiteral => Ok(Str(v.parse().or(Err(ParseError))?)),
IPv4Literal => Ok(Ip4(v.parse().or(Err(ParseError))?)),
IntegerLiteral => Ok(U64(v.parse().or(Err(ParseError))?)),
BooleanLiteral => Ok(Bool(v.parse().or(Err(ParseError))?)),
HexIntegerLiteral => {
let hex = v.strip_prefix("0x").unwrap();
let val: u64 = u64::from_str_radix(hex, 16).or(Err(ParseError))?;
Ok(U64(val))
},
_ => unreachable!()
}
}
pub fn method_lookup(&self, name: &str) -> Result<Self, Error> {
let obj = match self {
Val::Obj(obj) => obj,
_ => {
println!("no methods for non-object: {:?}", self.val_type());
return Err(TypeError);
}
};
let sym = obj.lookup_symbol(name).ok_or(NameError)?;
match sym {
Symbol::Func(fndef) => Ok(Val::Method(obj.clone(), fndef)),
_ => {
println!("calling non-func symbol: {}: {:?}", name, sym);
Err(TypeError)
}
}
}
pub fn lookup_symbol(&self, name: &str) -> Result<Symbol, Error> {
match self {
Val::Obj(obj) => obj.lookup_symbol(name).ok_or(NameError),
_ => {
println!("no symbols for non-object: {:?}", self.val_type());
Err(TypeError)
}
}
}
}
impl From<Packet> for Buf {
fn from(pkt: Packet) -> Self {
Self::from(pkt.as_ref())
}
}
impl From<Packet> for Val {
fn from(pkt: Packet) -> Self {
Self::Pkt(pkt.into())
}
}
impl From<Vec<Packet>> for Val {
fn from(pkts: Vec<Packet>) -> Self {
Self::PktGen(pkts.into())
}
}