use crate::blockchain::condition_opcode::ConditionOpcode;
use crate::blockchain::sized_bytes::*;
use crate::clvm::assemble::is_hex;
use crate::clvm::assemble::keywords::KEYWORD_FROM_ATOM;
use crate::clvm::program::Program;
use dg_xch_serialize::ChiaSerialize;
use hex::encode;
use num_bigint::BigInt;
use once_cell::sync::Lazy;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::fmt;
use std::fmt::{Debug, Display, Formatter};
use std::io::{Error, ErrorKind};
pub static NULL: Lazy<SExp> = Lazy::new(|| SExp::Atom(vec![].into()));
pub static ONE: Lazy<SExp> = Lazy::new(|| SExp::Atom(vec![1u8].into()));
#[derive(Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
pub enum SExp {
Atom(AtomBuf),
Pair(PairBuf),
}
impl SExp {
pub fn atom(&self) -> Result<&AtomBuf, Error> {
match self {
SExp::Atom(a) => Ok(a),
SExp::Pair(_) => Err(Error::new(
ErrorKind::Unsupported,
"Expected Atom, got Pair",
)),
}
}
pub fn pair(&self) -> Result<&PairBuf, Error> {
match self {
SExp::Atom(_) => Err(Error::new(
ErrorKind::Unsupported,
"Expected Pair, got Atom",
)),
SExp::Pair(p) => Ok(p),
}
}
pub fn first(&self) -> Result<&SExp, Error> {
match self {
SExp::Atom(_) => Err(Error::new(
ErrorKind::Unsupported,
"Expected Pair, got Atom",
)),
SExp::Pair(p) => Ok(&p.first),
}
}
pub fn rest(&self) -> Result<&SExp, Error> {
match self {
SExp::Atom(_) => Err(Error::new(
ErrorKind::Unsupported,
"Expected Pair, got Atom",
)),
SExp::Pair(p) => Ok(&p.rest),
}
}
pub fn cons(self, other: SExp) -> SExp {
SExp::Pair(PairBuf {
first: Box::new(self),
rest: Box::new(other),
})
}
pub fn split(self) -> Result<(SExp, SExp), Error> {
match self {
SExp::Atom(_) => Err(Error::new(
ErrorKind::Unsupported,
"Expected Pair, got Atom",
)),
SExp::Pair(p) => Ok((*p.first, *p.rest)),
}
}
pub fn nullp(&self) -> bool {
match &self {
SExp::Atom(a) => a.data.is_empty(),
_ => false,
}
}
pub fn as_atom_list(&self) -> Vec<Vec<u8>> {
match self {
SExp::Atom(_) => {
vec![]
}
SExp::Pair(pair) => match pair.first.as_ref() {
SExp::Atom(buf) => {
let mut rtn: Vec<Vec<u8>> = vec![buf.data.clone()];
rtn.extend(pair.rest.as_atom_list());
rtn
}
SExp::Pair(_) => {
vec![]
}
},
}
}
pub fn to_map(self) -> Result<HashMap<SExp, SExp>, Error> {
let mut rtn: HashMap<SExp, SExp> = HashMap::new();
let mut cur_node = self;
loop {
match cur_node {
SExp::Atom(_) => break,
SExp::Pair(pair) => {
cur_node = *pair.rest;
match *pair.first {
SExp::Atom(_) => {
rtn.insert(*pair.first, NULL.clone());
}
SExp::Pair(inner_pair) => {
rtn.insert(*inner_pair.first, *inner_pair.rest);
}
}
}
}
}
Ok(rtn)
}
pub fn arg_count_is(&self, mut count: usize) -> bool {
let mut ptr = self;
loop {
if count == 0 {
return ptr.nullp();
}
match ptr {
SExp::Pair(pair) => {
ptr = &pair.rest;
}
_ => return false,
}
count -= 1;
}
}
pub fn iter(&self) -> SExpIter {
SExpIter { c: self }
}
pub fn as_bool(&self) -> bool {
match self.atom() {
Ok(v0) => !v0.data.is_empty(),
_ => true,
}
}
pub fn from_bool(b: bool) -> &'static SExp {
if b {
&ONE
} else {
&NULL
}
}
pub fn proper_list(self, store: bool) -> Option<Vec<SExp>> {
let mut args = vec![];
let mut args_sexp = self;
loop {
match args_sexp {
SExp::Atom(_) => {
return if !args_sexp.non_nil() {
Some(args)
} else {
None
};
}
SExp::Pair(buf) => {
if store {
args.push(*buf.first);
}
args_sexp = *buf.rest;
}
}
}
}
pub fn non_nil(&self) -> bool {
match self {
SExp::Pair(_) => true,
SExp::Atom(b) => !b.data.is_empty(),
}
}
}
const PRINTABLE: &str = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ#!$%&'()*+,-./:;<=>?@[\\]^_`{|}~\"\r\n";
impl Display for SExp {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match &self {
SExp::Atom(a) => {
write!(f, "{}", a)
}
SExp::Pair(p) => {
write!(f, "{}", p)
}
}
}
}
impl Debug for SExp {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match &self {
SExp::Atom(a) => {
write!(f, "{}", a)
}
SExp::Pair(p) => {
write!(f, "{:?}", p)
}
}
}
}
pub struct SExpIter<'a> {
c: &'a SExp,
}
impl<'a> Iterator for SExpIter<'a> {
type Item = &'a SExp;
fn next(&mut self) -> Option<Self::Item> {
match self.c.pair().ok() {
Some(pair) => {
self.c = &pair.rest;
Some(&pair.first)
}
_ => None,
}
}
}
#[derive(Hash, Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
pub struct AtomBuf {
pub data: Vec<u8>,
}
impl Display for AtomBuf {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
if self.data.is_empty() {
f.write_str("()")
} else if self.data.len() > 2 {
match String::from_utf8(self.data.clone()) {
Ok(as_utf8) => {
for s in as_utf8.chars() {
if !PRINTABLE.contains(&s.to_string()) {
return f.write_str(&format!("0x{}", encode(&self.data)));
}
}
if as_utf8.contains('"') && as_utf8.contains('\'') {
f.write_str(&format!("0x{}", encode(&self.data)))
} else if as_utf8.contains('"') {
f.write_str(&format!("'{as_utf8}'"))
} else if as_utf8.contains('\'') {
f.write_str(&format!("\"{as_utf8}\""))
} else if is_hex(as_utf8.as_bytes()) {
f.write_str(&format!("0x{}", as_utf8))
} else {
f.write_str(&format!("\"{as_utf8}\""))
}
}
Err(_) => f.write_str(&format!("0x{}", encode(&self.data))),
}
} else if *self.data == BigInt::from_signed_bytes_be(&self.data).to_signed_bytes_be() {
f.write_str(&format!("{}", BigInt::from_signed_bytes_be(&self.data)))
} else {
f.write_str(&format!("0x{}", encode(&self.data)))
}
}
}
impl AtomBuf {
pub fn new(v: Vec<u8>) -> Self {
AtomBuf { data: v }
}
}
impl From<&[u8]> for AtomBuf {
fn from(v: &[u8]) -> Self {
Self::new(v.to_vec())
}
}
impl From<Vec<u8>> for AtomBuf {
fn from(v: Vec<u8>) -> Self {
Self::new(v)
}
}
impl From<&Vec<u8>> for AtomBuf {
fn from(v: &Vec<u8>) -> Self {
Self::from(v.clone())
}
}
impl PartialEq<&[u8]> for AtomBuf {
fn eq(&self, other: &&[u8]) -> bool {
self.data == *other
}
}
impl PartialEq<[u8]> for AtomBuf {
fn eq(&self, other: &[u8]) -> bool {
self.data == other
}
}
impl PartialEq<Vec<u8>> for AtomBuf {
fn eq(&self, other: &Vec<u8>) -> bool {
&self.data == other
}
}
#[derive(Hash, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct PairBuf {
pub first: Box<SExp>,
pub rest: Box<SExp>,
}
impl Display for PairBuf {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let mut buffer = String::from("(");
match &*self.first {
SExp::Atom(a) => {
if let Some(kw) = KEYWORD_FROM_ATOM.get(&a.data) {
buffer += kw;
} else {
buffer += &format!("{}", self.first);
}
}
SExp::Pair(_) => {
buffer += &format!("{}", self.first);
}
}
let mut current = &self.rest;
while let Ok(p) = current.pair() {
buffer += &format!(" {}", &p.first.as_ref());
current = &p.rest;
}
if current.non_nil() {
buffer += &format!(" . {}", *current);
}
buffer += ")";
write!(f, "{}", buffer)
}
}
impl Debug for PairBuf {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let mut buffer = String::from("(");
match &*self.first {
SExp::Atom(a) => {
buffer += &format!("{}", a);
}
SExp::Pair(p) => {
buffer += &format!("{:?}", p);
}
}
let mut current = &self.rest;
while let Ok(p) = current.pair() {
buffer += &format!(" {}", &p.first.as_ref());
current = &p.rest;
}
if current.non_nil() {
buffer += &format!(" . {}", *current);
}
buffer += ")";
write!(f, "{}", buffer)
}
}
impl From<(&SExp, &SExp)> for PairBuf {
fn from(v: (&SExp, &SExp)) -> Self {
PairBuf {
first: Box::new(v.0.clone()),
rest: Box::new(v.1.clone()),
}
}
}
impl From<(SExp, SExp)> for PairBuf {
fn from(v: (SExp, SExp)) -> Self {
PairBuf {
first: Box::new(v.0),
rest: Box::new(v.1),
}
}
}
pub trait IntoSExp {
fn to_sexp(self) -> SExp;
}
pub trait TryIntoSExp {
fn try_to_sexp(self) -> Result<SExp, Error>;
}
impl IntoSExp for Vec<SExp> {
fn to_sexp(self) -> SExp {
if let Some(sexp) = self.first().cloned() {
let mut end = NULL.clone();
if self.len() > 1 {
for other in self[1..].iter().rev() {
end = other.clone().cons(end);
}
}
sexp.cons(end)
} else {
NULL.clone()
}
}
}
impl<T: IntoSExp + Clone> IntoSExp for &[T] {
fn to_sexp(self) -> SExp {
self.iter()
.cloned()
.map(|v| v.to_sexp())
.collect::<Vec<SExp>>()
.to_sexp()
}
}
impl<T: IntoSExp> IntoSExp for Vec<T> {
fn to_sexp(self) -> SExp {
self.into_iter()
.map(|v| v.to_sexp())
.collect::<Vec<SExp>>()
.to_sexp()
}
}
impl<T: IntoSExp> IntoSExp for (T, T) {
fn to_sexp(self) -> SExp {
self.0.to_sexp().cons(self.1.to_sexp().cons(NULL.clone()))
}
}
impl IntoSExp for (SExp, SExp) {
fn to_sexp(self) -> SExp {
self.0.cons(self.1)
}
}
impl IntoSExp for &str {
fn to_sexp(self) -> SExp {
SExp::Atom(AtomBuf::new(self.as_bytes().to_vec()))
}
}
impl IntoSExp for String {
fn to_sexp(self) -> SExp {
SExp::Atom(AtomBuf::new(self.as_bytes().to_vec()))
}
}
impl IntoSExp for Program {
fn to_sexp(self) -> SExp {
self.sexp.clone()
}
}
impl IntoSExp for ConditionOpcode {
fn to_sexp(self) -> SExp {
SExp::Atom(AtomBuf::new(self.to_bytes()))
}
}
macro_rules! impl_to_sexp_sized_bytes {
($($name: ident);*) => {
$(
impl IntoSExp for $name {
fn to_sexp(self) -> SExp {
SExp::Atom(AtomBuf::new(self.as_slice().to_vec()))
}
}
)*
};
()=>{};
}
impl_to_sexp_sized_bytes!(
Bytes4;
Bytes8;
Bytes32;
Bytes48;
Bytes96;
Bytes100;
Bytes480
);
macro_rules! impl_ints {
($($name: ident);*) => {
$(
impl IntoSExp for $name {
fn to_sexp(self) -> SExp {
if self == 0 {
return SExp::Atom(AtomBuf::new(vec![]));
}
let as_ary = self.to_be_bytes();
let mut as_bytes = as_ary.as_slice();
while as_bytes.len() > 1 && as_bytes[0] == ( if as_bytes[1] & 0x80 > 0{0xFF} else {0}) {
as_bytes = &as_bytes[1..];
}
SExp::Atom(AtomBuf::new(as_bytes.to_vec()))
}
}
)*
};
()=>{};
}
impl_ints!(
u8;
u16;
u32;
u64;
u128;
i8;
i16;
i32;
i64;
i128
);