use std::convert::TryFrom;
use ergo_lib::{
ergo_chain_types::Base16DecodedBytes, ergotree_ir::serialization::SigmaSerializable,
};
use crate::{
constant::{ConstConstantPtr, Constant, ConstantPtr},
util::{const_ptr_as_ref, mut_ptr_as_mut},
Error,
};
#[derive(PartialEq, Eq, Debug, Clone)]
pub struct ErgoTree(pub(crate) ergo_lib::ergotree_ir::ergo_tree::ErgoTree);
pub type ErgoTreePtr = *mut ErgoTree;
pub type ConstErgoTreePtr = *const ErgoTree;
pub unsafe fn ergo_tree_from_base16_bytes(
bytes_str: &str,
ergo_tree_out: *mut ErgoTreePtr,
) -> Result<(), Error> {
let ergo_tree_out = mut_ptr_as_mut(ergo_tree_out, "ergo_tree_out")?;
let bytes = Base16DecodedBytes::try_from(bytes_str.to_string())?.0;
let ergo_tree =
ergo_lib::ergotree_ir::ergo_tree::ErgoTree::sigma_parse_bytes(&bytes).map(ErgoTree)?;
*ergo_tree_out = Box::into_raw(Box::new(ergo_tree));
Ok(())
}
pub unsafe fn ergo_tree_from_bytes(
bytes_ptr: *const u8,
len: usize,
ergo_tree_out: *mut ErgoTreePtr,
) -> Result<(), Error> {
if bytes_ptr.is_null() {
return Err(Error::Misc("bytes_ptr is null".into()));
}
let bytes = std::slice::from_raw_parts(bytes_ptr, len);
let ergo_tree_out = mut_ptr_as_mut(ergo_tree_out, "ergo_tree_out")?;
let ergo_tree =
ergo_lib::ergotree_ir::ergo_tree::ErgoTree::sigma_parse_bytes(bytes).map(ErgoTree)?;
*ergo_tree_out = Box::into_raw(Box::new(ergo_tree));
Ok(())
}
pub unsafe fn ergo_tree_bytes_len(ergo_tree_ptr: ConstErgoTreePtr) -> Result<usize, Error> {
let ergo_tree = const_ptr_as_ref(ergo_tree_ptr, "ergo_tree_ptr")?;
let len = ergo_tree.0.sigma_serialize_bytes().map(|v| v.len())?;
Ok(len)
}
pub unsafe fn ergo_tree_to_bytes(
ergo_tree_ptr: ConstErgoTreePtr,
output: *mut u8,
) -> Result<(), Error> {
let ergo_tree = const_ptr_as_ref(ergo_tree_ptr, "ergo_tree_ptr")?;
let src = ergo_tree.0.sigma_serialize_bytes()?;
std::ptr::copy_nonoverlapping(src.as_ptr(), output, src.len());
Ok(())
}
pub unsafe fn ergo_tree_to_base16_bytes(ergo_tree_ptr: ConstErgoTreePtr) -> Result<String, Error> {
let ergo_tree = const_ptr_as_ref(ergo_tree_ptr, "ergo_tree_ptr")?;
let s = ergo_tree.0.to_base16_bytes()?;
Ok(s)
}
pub unsafe fn ergo_tree_constants_len(ergo_tree_ptr: ConstErgoTreePtr) -> Result<usize, Error> {
let ergo_tree = const_ptr_as_ref(ergo_tree_ptr, "ergo_tree_ptr")?;
let len = ergo_tree.0.constants_len()?;
Ok(len)
}
pub unsafe fn ergo_tree_get_constant(
ergo_tree_ptr: ConstErgoTreePtr,
index: usize,
constant_out: *mut ConstantPtr,
) -> Result<bool, Error> {
let ergo_tree = const_ptr_as_ref(ergo_tree_ptr, "ergo_tree_ptr")?;
let constant_out = mut_ptr_as_mut(constant_out, "constant_out")?;
let constant = ergo_tree.0.get_constant(index).map(|c| c.map(Constant))?;
if let Some(constant) = constant {
*constant_out = Box::into_raw(Box::new(constant));
Ok(true)
} else {
Ok(false)
}
}
pub unsafe fn ergo_tree_with_constant(
ergo_tree_ptr: ConstErgoTreePtr,
index: usize,
constant_ptr: ConstConstantPtr,
ergo_tree_out: *mut ErgoTreePtr,
) -> Result<(), Error> {
let ergo_tree_cloned = const_ptr_as_ref(ergo_tree_ptr, "ergo_tree_ptr")?.clone();
let constant = const_ptr_as_ref(constant_ptr, "constant_ptr")?;
let ergo_tree_out = mut_ptr_as_mut(ergo_tree_out, "ergo_tree_out")?;
let new_inner = ergo_tree_cloned
.0
.with_constant(index, constant.0.clone())?;
*ergo_tree_out = Box::into_raw(Box::new(ErgoTree(new_inner)));
Ok(())
}
pub unsafe fn ergo_tree_template_bytes_len(
ergo_tree_ptr: ConstErgoTreePtr,
) -> Result<usize, Error> {
let ergo_tree = const_ptr_as_ref(ergo_tree_ptr, "ergo_tree_ptr")?;
let len = ergo_tree.0.template_bytes().map(|v| v.len())?;
Ok(len)
}
pub unsafe fn ergo_tree_template_bytes(
ergo_tree_ptr: ConstErgoTreePtr,
output: *mut u8,
) -> Result<(), Error> {
let ergo_tree = const_ptr_as_ref(ergo_tree_ptr, "ergo_tree_ptr")?;
let src = ergo_tree.0.template_bytes()?;
std::ptr::copy_nonoverlapping(src.as_ptr(), output, src.len());
Ok(())
}