use libc::c_int;
use std::ffi::{CStr, CString};
use std::marker;
use std::mem;
use super::JsonnetVm;
use jsonnet_sys::{self, JsonnetJsonValue};
pub struct JsonVal<'a> {
vm: &'a JsonnetVm,
value: *const JsonnetJsonValue,
}
impl<'a> JsonVal<'a> {
pub unsafe fn from_ptr(vm: &'a JsonnetVm, p: *const JsonnetJsonValue) -> Self {
JsonVal { vm: vm, value: p }
}
pub fn as_ptr(&self) -> *const JsonnetJsonValue {
self.value
}
pub fn as_str(&self) -> Option<&str> {
unsafe {
let p = jsonnet_sys::jsonnet_json_extract_string(self.vm.as_ptr(), self.as_ptr());
if p.is_null() {
None
} else {
Some(CStr::from_ptr(p).to_str().unwrap())
}
}
}
pub fn as_num(&self) -> Option<f64> {
let mut number = 0.0;
let ok = unsafe {
jsonnet_sys::jsonnet_json_extract_number(self.vm.as_ptr(), self.as_ptr(), &mut number)
};
if ok != 0 {
Some(number)
} else {
None
}
}
pub fn as_bool(&self) -> Option<bool> {
let v = unsafe { jsonnet_sys::jsonnet_json_extract_bool(self.vm.as_ptr(), self.as_ptr()) };
match v {
0 => Some(false),
1 => Some(true),
2 => None,
_ => unreachable!(),
}
}
pub fn as_null(&self) -> Option<()> {
let v = unsafe { jsonnet_sys::jsonnet_json_extract_null(self.vm.as_ptr(), self.as_ptr()) };
match v {
0 => None,
1 => Some(()),
_ => unreachable!(),
}
}
}
pub struct JsonValue<'a> {
vm: &'a JsonnetVm,
value: *mut JsonnetJsonValue,
_marker: marker::PhantomData<JsonnetJsonValue>,
}
impl<'a> JsonValue<'a> {
pub unsafe fn from_ptr(vm: &'a JsonnetVm, p: *mut JsonnetJsonValue) -> Self {
JsonValue {
vm: vm,
value: p,
_marker: marker::PhantomData,
}
}
pub fn as_ptr(&self) -> *const JsonnetJsonValue {
self.value
}
pub fn as_str(&self) -> Option<&str> {
unsafe {
let p = jsonnet_sys::jsonnet_json_extract_string(self.vm.as_ptr(), self.as_ptr());
if p.is_null() {
None
} else {
Some(CStr::from_ptr(p).to_str().unwrap())
}
}
}
pub fn as_num(&self) -> Option<f64> {
let mut number = 0.0;
let ok = unsafe {
jsonnet_sys::jsonnet_json_extract_number(self.vm.as_ptr(), self.as_ptr(), &mut number)
};
if ok != 0 {
Some(number)
} else {
None
}
}
pub fn as_bool(&self) -> Option<bool> {
let v = unsafe { jsonnet_sys::jsonnet_json_extract_bool(self.vm.as_ptr(), self.as_ptr()) };
match v {
0 => Some(false),
1 => Some(true),
2 => None,
_ => unreachable!(),
}
}
pub fn as_null(&self) -> Option<()> {
let v = unsafe { jsonnet_sys::jsonnet_json_extract_null(self.vm.as_ptr(), self.as_ptr()) };
match v {
0 => None,
1 => Some(()),
_ => unreachable!(),
}
}
pub fn from_str(vm: &'a JsonnetVm, v: &str) -> Self {
let cstr = CString::new(v).unwrap();
unsafe {
let p = jsonnet_sys::jsonnet_json_make_string(vm.as_ptr(), cstr.as_ptr());
Self::from_ptr(vm, p)
}
}
pub fn from_num(vm: &'a JsonnetVm, v: f64) -> Self {
unsafe {
let p = jsonnet_sys::jsonnet_json_make_number(vm.as_ptr(), v);
Self::from_ptr(vm, p)
}
}
pub fn from_bool(vm: &'a JsonnetVm, v: bool) -> Self {
unsafe {
let p = jsonnet_sys::jsonnet_json_make_bool(vm.as_ptr(), v as c_int);
Self::from_ptr(vm, p)
}
}
pub fn null(vm: &'a JsonnetVm) -> Self {
unsafe {
let p = jsonnet_sys::jsonnet_json_make_null(vm.as_ptr());
Self::from_ptr(vm, p)
}
}
pub fn from_array<T>(vm: &'a JsonnetVm, iter: T) -> Self
where
T: IntoIterator<Item = JsonValue<'a>>,
{
unsafe {
let p = jsonnet_sys::jsonnet_json_make_array(vm.as_ptr());
for item in iter {
jsonnet_sys::jsonnet_json_array_append(vm.as_ptr(), p, item.into_raw());
}
Self::from_ptr(vm, p)
}
}
pub fn from_map<'b, T>(vm: &'a JsonnetVm, iter: T) -> Self
where
T: IntoIterator<Item = (&'b CStr, JsonValue<'a>)>,
{
unsafe {
let p = jsonnet_sys::jsonnet_json_make_object(vm.as_ptr());
for (f, v) in iter {
jsonnet_sys::jsonnet_json_object_append(vm.as_ptr(), p, f.as_ptr(), v.into_raw());
}
Self::from_ptr(vm, p)
}
}
pub fn into_raw(self) -> *mut JsonnetJsonValue {
let result = self.value;
mem::forget(self);
result
}
}
impl<'a> Drop for JsonValue<'a> {
fn drop(&mut self) {
unsafe {
jsonnet_sys::jsonnet_json_destroy(self.vm.as_ptr(), self.value);
}
}
}