use core::{
fmt, marker::PhantomData, ops::Deref, ptr, ptr::NonNull, slice, str,
};
use crate::c;
#[derive(Copy, Clone)]
#[repr(transparent)]
pub struct Object<'a> {
c: c::GgObject,
phantom: PhantomData<UnpackedObject<'a>>,
}
impl fmt::Debug for Object<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.unpack().fmt(f)
}
}
#[derive(Debug)]
#[repr(u8)]
pub enum UnpackedObject<'a> {
Null = 0,
Bool(bool) = 1,
I64(i64) = 2,
F64(f64) = 3,
Buf(&'a str) = 4,
List(List<'a>) = 5,
Map(Map<'a>) = 6,
}
impl<'a> Object<'a> {
pub const NULL: Self = Self {
c: c::GgObject { _private: [0; _] },
phantom: PhantomData,
};
#[must_use]
pub fn bool(b: bool) -> Self {
Self {
c: unsafe { c::gg_obj_bool(b) },
phantom: PhantomData,
}
}
#[must_use]
pub fn i64(i: i64) -> Self {
Self {
c: unsafe { c::gg_obj_i64(i) },
phantom: PhantomData,
}
}
#[must_use]
pub fn f64(f: f64) -> Self {
Self {
c: unsafe { c::gg_obj_f64(f) },
phantom: PhantomData,
}
}
#[must_use]
pub fn buf(buf: &'a str) -> Self {
Self {
c: unsafe { c::gg_obj_buf(buf.into()) },
phantom: PhantomData,
}
}
#[must_use]
pub fn list(list: &'a [Object<'a>]) -> Self {
Self {
c: unsafe { c::gg_obj_list(list.into()) },
phantom: PhantomData,
}
}
#[must_use]
pub fn map(map: &'a [Kv<'a>]) -> Self {
Self {
c: unsafe { c::gg_obj_map(map.into()) },
phantom: PhantomData,
}
}
}
unsafe fn slice_from_c<'a, T>(ptr: *const T, len: usize) -> &'a [T] {
let ptr = NonNull::new(ptr.cast_mut()).unwrap_or_else(|| {
assert_eq!(len, 0, "null pointer with non-zero length");
NonNull::dangling()
});
unsafe { NonNull::slice_from_raw_parts(ptr, len).as_ref() }
}
impl<'a> Object<'a> {
#[must_use]
pub fn unpack(&self) -> UnpackedObject<'_> {
use c::GgObjectType::*;
unsafe {
match c::gg_obj_type(self.c) {
GG_TYPE_NULL => UnpackedObject::Null,
GG_TYPE_BOOLEAN => {
UnpackedObject::Bool(c::gg_obj_into_bool(self.c))
}
GG_TYPE_I64 => UnpackedObject::I64(c::gg_obj_into_i64(self.c)),
GG_TYPE_F64 => UnpackedObject::F64(c::gg_obj_into_f64(self.c)),
GG_TYPE_BUF => {
let buf = c::gg_obj_into_buf(self.c);
let ptr = slice_from_c(buf.data, buf.len);
UnpackedObject::Buf(str::from_utf8_unchecked(ptr))
}
GG_TYPE_LIST => {
let list = c::gg_obj_into_list(self.c);
UnpackedObject::List(List(slice_from_c(
list.items.cast::<Object<'a>>(),
list.len,
)))
}
GG_TYPE_MAP => {
let map = c::gg_obj_into_map(self.c);
UnpackedObject::Map(Map(slice_from_c(
map.pairs.cast::<Kv<'a>>(),
map.len,
)))
}
}
}
}
}
impl Default for Object<'_> {
fn default() -> Self {
Self::NULL
}
}
impl From<bool> for Object<'_> {
fn from(b: bool) -> Self {
Self::bool(b)
}
}
impl From<i64> for Object<'_> {
fn from(i: i64) -> Self {
Self::i64(i)
}
}
impl From<f64> for Object<'_> {
fn from(f: f64) -> Self {
Self::f64(f)
}
}
impl<'a> From<&'a str> for Object<'a> {
fn from(s: &'a str) -> Self {
Self::buf(s)
}
}
impl<'a> From<&'a [Object<'a>]> for Object<'a> {
fn from(list: &'a [Object<'a>]) -> Self {
Self::list(list)
}
}
impl<'a> From<&'a [Kv<'a>]> for Object<'a> {
fn from(map: &'a [Kv<'a>]) -> Self {
Self::map(map)
}
}
impl<'a> From<Map<'a>> for Object<'a> {
fn from(map: Map<'a>) -> Self {
Self::map(map.0)
}
}
impl<'a> From<List<'a>> for Object<'a> {
fn from(list: List<'a>) -> Self {
Self::list(list.0)
}
}
#[derive(Copy, Clone)]
#[repr(transparent)]
pub struct Kv<'a> {
c: c::GgKV,
phantom_key: PhantomData<&'a str>,
phantom_value: PhantomData<Object<'a>>,
}
impl fmt::Debug for Kv<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Kv")
.field("key", &self.key())
.field("val", self.val())
.finish()
}
}
impl<'a> Kv<'a> {
#[must_use]
pub fn new(key: &'a str, value: Object<'a>) -> Self {
Self {
c: unsafe { c::gg_kv(key.into(), value.c) },
phantom_key: PhantomData,
phantom_value: PhantomData,
}
}
#[must_use]
pub fn key(&self) -> &str {
let buf = unsafe { c::gg_kv_key(self.c) };
unsafe {
str::from_utf8_unchecked(slice::from_raw_parts(buf.data, buf.len))
}
}
#[must_use]
pub fn val(&self) -> &Object<'a> {
unsafe {
c::gg_kv_val((&raw const self.c).cast_mut())
.cast::<Object>()
.as_ref()
.unwrap_unchecked()
}
}
}
impl<'a> From<Map<'a>> for &'a [Kv<'a>] {
fn from(map: Map<'a>) -> Self {
map.0
}
}
impl<'a> From<List<'a>> for &'a [Object<'a>] {
fn from(list: List<'a>) -> Self {
list.0
}
}
#[derive(Debug, Clone, Copy)]
#[repr(transparent)]
pub struct Map<'a>(pub &'a [Kv<'a>]);
#[derive(Debug, Clone, Copy)]
#[repr(transparent)]
pub struct List<'a>(pub &'a [Object<'a>]);
impl Map<'_> {
#[must_use]
pub fn get(&self, key: &str) -> Option<&Object<'_>> {
let map: c::GgMap = self.0.into();
let mut result: *mut c::GgObject = ptr::null_mut();
if unsafe { c::gg_map_get(map, key.into(), &raw mut result) } {
Some(unsafe {
NonNull::new(result.cast::<Object>())
.unwrap_unchecked()
.as_ref()
})
} else {
None
}
}
}
impl<'a> From<&'a [Kv<'a>]> for Map<'a> {
fn from(slice: &'a [Kv<'a>]) -> Self {
Map(slice)
}
}
impl From<&[Kv<'_>]> for c::GgMap {
fn from(kvs: &[Kv<'_>]) -> Self {
Self {
pairs: kvs.as_ptr().cast_mut().cast::<c::GgKV>(),
len: kvs.len(),
}
}
}
impl<'a> From<&'a [Object<'a>]> for List<'a> {
fn from(slice: &'a [Object<'a>]) -> Self {
List(slice)
}
}
impl From<&[Object<'_>]> for c::GgList {
fn from(objs: &[Object<'_>]) -> Self {
Self {
items: objs.as_ptr().cast_mut().cast::<c::GgObject>(),
len: objs.len(),
}
}
}
impl<'a> Deref for Map<'a> {
type Target = [Kv<'a>];
fn deref(&self) -> &[Kv<'a>] {
self.0
}
}
impl<'a> Deref for List<'a> {
type Target = [Object<'a>];
fn deref(&self) -> &[Object<'a>] {
self.0
}
}