use alloc::string::String;
use alloc::vec::Vec;
use core::fmt;
use azul_css::{AzString, OptionString, OptionF64, impl_vec, impl_vec_clone, impl_vec_debug, impl_vec_partialeq, impl_vec_mut, impl_result, impl_result_inner, impl_option, impl_option_inner};
#[cfg(feature = "json")]
use serde_json::Value;
#[derive(Debug, Clone, PartialEq)]
#[repr(C)]
pub struct Json {
pub value_type: JsonType,
pub internal: JsonInternal,
}
#[derive(Debug, Clone, PartialEq)]
#[repr(C)]
pub struct JsonInternal {
string_value: AzString,
number_value: f64,
bool_value: bool,
}
impl Default for JsonInternal {
fn default() -> Self {
Self {
string_value: AzString::from(String::new()),
number_value: 0.0,
bool_value: false,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(C)]
pub enum JsonType {
Null,
Bool,
Number,
String,
Array,
Object,
}
#[derive(Debug, Clone, PartialEq)]
#[repr(C)]
pub struct JsonParseError {
pub message: AzString,
pub line: u32,
pub column: u32,
}
impl fmt::Display for JsonParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.line > 0 {
write!(f, "{}:{}: {}", self.line, self.column, self.message.as_str())
} else {
write!(f, "{}", self.message.as_str())
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for JsonParseError {}
#[derive(Debug, Clone, PartialEq)]
#[repr(C)]
pub struct JsonKeyValue {
pub key: AzString,
pub value: Json,
}
impl JsonKeyValue {
pub fn create(key: AzString, value: Json) -> Self {
Self { key, value }
}
}
impl_option!(JsonKeyValue, OptionJsonKeyValue, copy = false, [Debug, Clone, PartialEq]);
impl_vec!(JsonKeyValue, JsonKeyValueVec, JsonKeyValueVecDestructor, JsonKeyValueVecDestructorType, JsonKeyValueVecSlice, OptionJsonKeyValue);
impl_vec_clone!(JsonKeyValue, JsonKeyValueVec, JsonKeyValueVecDestructor);
impl_vec_debug!(JsonKeyValue, JsonKeyValueVec);
impl JsonKeyValueVec {
#[inline]
pub fn copy_from_array(ptr: *const JsonKeyValue, len: usize) -> Self {
if ptr.is_null() || len == 0 {
return Self::new();
}
let slice = unsafe { core::slice::from_raw_parts(ptr, len) };
Self::from_vec(slice.iter().cloned().collect())
}
}
impl_vec!(Json, JsonVec, JsonVecDestructor, JsonVecDestructorType, JsonVecSlice, OptionJson);
impl_vec_clone!(Json, JsonVec, JsonVecDestructor);
impl_vec_debug!(Json, JsonVec);
impl_vec_partialeq!(Json, JsonVec);
impl_vec_mut!(Json, JsonVec);
impl JsonVec {
#[inline]
pub fn copy_from_array(ptr: *const Json, len: usize) -> Self {
if ptr.is_null() || len == 0 {
return Self::new();
}
let slice = unsafe { core::slice::from_raw_parts(ptr, len) };
Self::from_vec(slice.iter().cloned().collect())
}
}
impl_result!(
Json,
JsonParseError,
ResultJsonJsonParseError,
copy = false,
[Debug, Clone, PartialEq]
);
impl_option!(Json, OptionJson, copy = false, [Clone, Debug, PartialEq]);
impl_option!(JsonVec, OptionJsonVec, copy = false, [Clone, Debug]);
impl_option!(JsonKeyValueVec, OptionJsonKeyValueVec, copy = false, [Clone, Debug]);
pub use azul_css::OptionBool;
impl_option!(i64, OptionI64, [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]);
impl Json {
#[cfg(feature = "json")]
pub fn parse(s: &str) -> Result<Self, JsonParseError> {
let value: Value = serde_json::from_str(s).map_err(|e| {
JsonParseError {
message: AzString::from(e.to_string()),
line: e.line() as u32,
column: e.column() as u32,
}
})?;
Ok(Self::from_serde_value(value))
}
#[cfg(feature = "json")]
pub fn parse_bytes(bytes: &[u8]) -> Result<Self, JsonParseError> {
let value: Value = serde_json::from_slice(bytes).map_err(|e| {
JsonParseError {
message: AzString::from(e.to_string()),
line: e.line() as u32,
column: e.column() as u32,
}
})?;
Ok(Self::from_serde_value(value))
}
#[cfg(feature = "json")]
fn from_serde_value(value: Value) -> Self {
match value {
Value::Null => Self::null(),
Value::Bool(b) => Self::bool(b),
Value::Number(n) => Self::number(n.as_f64().unwrap_or(0.0)),
Value::String(s) => Self::string(s),
Value::Array(arr) => {
let json_str = serde_json::to_string(&Value::Array(arr)).unwrap_or_default();
Self {
value_type: JsonType::Array,
internal: JsonInternal {
string_value: AzString::from(json_str),
number_value: 0.0,
bool_value: false,
},
}
}
Value::Object(obj) => {
let json_str = serde_json::to_string(&Value::Object(obj)).unwrap_or_default();
Self {
value_type: JsonType::Object,
internal: JsonInternal {
string_value: AzString::from(json_str),
number_value: 0.0,
bool_value: false,
},
}
}
}
}
pub fn null() -> Self {
Self {
value_type: JsonType::Null,
internal: JsonInternal::default(),
}
}
pub fn bool(value: bool) -> Self {
Self {
value_type: JsonType::Bool,
internal: JsonInternal {
string_value: AzString::from(String::new()),
number_value: 0.0,
bool_value: value,
},
}
}
pub fn number(value: f64) -> Self {
Self {
value_type: JsonType::Number,
internal: JsonInternal {
string_value: AzString::from(String::new()),
number_value: value,
bool_value: false,
},
}
}
pub fn integer(value: i64) -> Self {
Self {
value_type: JsonType::Number,
internal: JsonInternal {
string_value: AzString::from(String::new()),
number_value: value as f64,
bool_value: false,
},
}
}
pub fn string(value: impl Into<String>) -> Self {
Self {
value_type: JsonType::String,
internal: JsonInternal {
string_value: AzString::from(value.into()),
number_value: 0.0,
bool_value: false,
},
}
}
#[cfg(feature = "json")]
pub fn array(values: JsonVec) -> Self {
let serde_array: Vec<serde_json::Value> = values
.as_slice()
.iter()
.map(|j| j.to_serde_value())
.collect();
let json_str = serde_json::to_string(&serde_json::Value::Array(serde_array))
.unwrap_or_else(|_| "[]".to_string());
Self {
value_type: JsonType::Array,
internal: JsonInternal {
string_value: AzString::from(json_str),
number_value: 0.0,
bool_value: false,
},
}
}
#[cfg(feature = "json")]
pub fn object(entries: JsonKeyValueVec) -> Self {
let mut map = serde_json::Map::new();
for kv in entries.as_slice() {
map.insert(kv.key.as_str().to_string(), kv.value.to_serde_value());
}
let json_str = serde_json::to_string(&serde_json::Value::Object(map))
.unwrap_or_else(|_| "{}".to_string());
Self {
value_type: JsonType::Object,
internal: JsonInternal {
string_value: AzString::from(json_str),
number_value: 0.0,
bool_value: false,
},
}
}
#[cfg(feature = "json")]
fn to_serde_value(&self) -> serde_json::Value {
match self.value_type {
JsonType::Null => serde_json::Value::Null,
JsonType::Bool => serde_json::Value::Bool(self.internal.bool_value),
JsonType::Number => {
let num = self.internal.number_value;
if num.fract() == 0.0 && num >= i64::MIN as f64 && num <= i64::MAX as f64 {
serde_json::Value::Number(serde_json::Number::from(num as i64))
} else {
serde_json::Number::from_f64(num)
.map(serde_json::Value::Number)
.unwrap_or(serde_json::Value::Null)
}
}
JsonType::String => serde_json::Value::String(self.internal.string_value.as_str().to_string()),
JsonType::Array | JsonType::Object => {
serde_json::from_str(self.internal.string_value.as_str())
.unwrap_or(serde_json::Value::Null)
}
}
}
pub fn is_null(&self) -> bool {
self.value_type == JsonType::Null
}
pub fn is_bool(&self) -> bool {
self.value_type == JsonType::Bool
}
pub fn is_number(&self) -> bool {
self.value_type == JsonType::Number
}
pub fn is_string(&self) -> bool {
self.value_type == JsonType::String
}
pub fn is_array(&self) -> bool {
self.value_type == JsonType::Array
}
pub fn is_object(&self) -> bool {
self.value_type == JsonType::Object
}
pub fn as_bool(&self) -> OptionBool {
if self.value_type == JsonType::Bool {
OptionBool::Some(self.internal.bool_value)
} else {
OptionBool::None
}
}
pub fn as_number(&self) -> OptionF64 {
if self.value_type == JsonType::Number {
OptionF64::Some(self.internal.number_value)
} else {
OptionF64::None
}
}
pub fn as_i64(&self) -> OptionI64 {
if self.value_type == JsonType::Number {
let n = self.internal.number_value;
if n.fract() == 0.0 && n >= i64::MIN as f64 && n <= i64::MAX as f64 {
OptionI64::Some(n as i64)
} else {
OptionI64::None
}
} else {
OptionI64::None
}
}
pub fn as_string(&self) -> OptionString {
if self.value_type == JsonType::String {
OptionString::Some(self.internal.string_value.clone())
} else {
OptionString::None
}
}
#[cfg(feature = "json")]
pub fn len(&self) -> usize {
match self.value_type {
JsonType::Array => {
if let Ok(Value::Array(arr)) = serde_json::from_str(self.internal.string_value.as_str()) {
arr.len()
} else {
0
}
}
JsonType::Object => {
if let Ok(Value::Object(obj)) = serde_json::from_str(self.internal.string_value.as_str()) {
obj.len()
} else {
0
}
}
_ => 0,
}
}
#[cfg(feature = "json")]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[cfg(feature = "json")]
pub fn get_index(&self, index: usize) -> Option<Json> {
if self.value_type != JsonType::Array {
return None;
}
let value: Value = serde_json::from_str(self.internal.string_value.as_str()).ok()?;
if let Value::Array(arr) = value {
arr.get(index).map(|v| Self::from_serde_value(v.clone()))
} else {
None
}
}
#[cfg(feature = "json")]
pub fn get_key(&self, key: &str) -> Option<Json> {
if self.value_type != JsonType::Object {
return None;
}
let value: Value = serde_json::from_str(self.internal.string_value.as_str()).ok()?;
if let Value::Object(obj) = value {
obj.get(key).map(|v| Self::from_serde_value(v.clone()))
} else {
None
}
}
#[cfg(feature = "json")]
pub fn keys(&self) -> Vec<AzString> {
if self.value_type != JsonType::Object {
return Vec::new();
}
let value: Value = match serde_json::from_str(self.internal.string_value.as_str()) {
Ok(v) => v,
Err(_) => return Vec::new(),
};
if let Value::Object(obj) = value {
obj.keys().map(|k| AzString::from(k.clone())).collect()
} else {
Vec::new()
}
}
#[cfg(feature = "json")]
pub fn to_array(&self) -> Option<JsonVec> {
if self.value_type != JsonType::Array {
return None;
}
let value: Value = serde_json::from_str(self.internal.string_value.as_str()).ok()?;
if let Value::Array(arr) = value {
Some(arr.into_iter().map(Self::from_serde_value).collect())
} else {
None
}
}
#[cfg(feature = "json")]
pub fn to_object(&self) -> Option<JsonKeyValueVec> {
if self.value_type != JsonType::Object {
return None;
}
let value: Value = serde_json::from_str(self.internal.string_value.as_str()).ok()?;
if let Value::Object(obj) = value {
Some(obj.into_iter().map(|(k, v)| JsonKeyValue {
key: AzString::from(k),
value: Self::from_serde_value(v),
}).collect())
} else {
None
}
}
#[cfg(feature = "json")]
pub fn to_string(&self) -> AzString {
match self.value_type {
JsonType::Null => AzString::from("null".to_string()),
JsonType::Bool => AzString::from(if self.internal.bool_value { "true" } else { "false" }.to_string()),
JsonType::Number => {
let num = self.internal.number_value;
if num.fract() == 0.0 && num >= i64::MIN as f64 && num <= i64::MAX as f64 {
AzString::from((num as i64).to_string())
} else {
AzString::from(num.to_string())
}
}
JsonType::String => {
let escaped = serde_json::to_string(self.internal.string_value.as_str()).unwrap_or_default();
AzString::from(escaped)
}
JsonType::Array | JsonType::Object => {
self.internal.string_value.clone()
}
}
}
#[cfg(feature = "json")]
pub fn to_string_pretty(&self) -> AzString {
match self.value_type {
JsonType::Null | JsonType::Bool | JsonType::Number | JsonType::String => {
self.to_string()
}
JsonType::Array | JsonType::Object => {
if let Ok(value) = serde_json::from_str::<Value>(self.internal.string_value.as_str()) {
AzString::from(serde_json::to_string_pretty(&value).unwrap_or_default())
} else {
self.internal.string_value.clone()
}
}
}
}
#[cfg(feature = "json")]
pub fn jq(&self, path: &str) -> Json {
match self.value_type {
JsonType::Null | JsonType::Bool | JsonType::Number | JsonType::String => {
if path.is_empty() {
self.clone()
} else {
Json::null()
}
}
JsonType::Array | JsonType::Object => {
let value: Value = match serde_json::from_str(self.internal.string_value.as_str()) {
Ok(v) => v,
Err(_) => return Json::null(),
};
match value.pointer(path) {
Some(v) => Self::from_serde_value(v.clone()),
None => Json::null(),
}
}
}
}
#[cfg(feature = "json")]
pub fn jq_all(&self, path: &str) -> JsonVec {
let result = match self.value_type {
JsonType::Null | JsonType::Bool | JsonType::Number | JsonType::String => {
if path.is_empty() {
vec![self.clone()]
} else {
vec![]
}
}
JsonType::Array | JsonType::Object => {
let value: Value = match serde_json::from_str(self.internal.string_value.as_str()) {
Ok(v) => v,
Err(_) => return JsonVec::from_vec(vec![]),
};
Self::jq_all_recursive(&value, path)
}
};
JsonVec::from_vec(result)
}
#[cfg(feature = "json")]
fn jq_all_recursive(value: &Value, path: &str) -> Vec<Json> {
if path.is_empty() {
return vec![Self::from_serde_value(value.clone())];
}
if !path.starts_with('/') {
return vec![];
}
let rest = &path[1..]; let (component, remaining) = match rest.find('/') {
Some(idx) => (&rest[..idx], &rest[idx..]),
None => (rest, ""),
};
if component == "*" {
let mut results = Vec::new();
match value {
Value::Array(arr) => {
for item in arr {
results.extend(Self::jq_all_recursive(item, remaining));
}
}
Value::Object(obj) => {
for (_key, val) in obj {
results.extend(Self::jq_all_recursive(val, remaining));
}
}
_ => {} }
results
} else {
match value {
Value::Array(arr) => {
if let Ok(idx) = component.parse::<usize>() {
if let Some(item) = arr.get(idx) {
return Self::jq_all_recursive(item, remaining);
}
}
vec![]
}
Value::Object(obj) => {
if let Some(val) = obj.get(component) {
return Self::jq_all_recursive(val, remaining);
}
vec![]
}
_ => vec![],
}
}
}
}
impl fmt::Display for Json {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
#[cfg(feature = "json")]
{
write!(f, "{}", self.to_string().as_str())
}
#[cfg(not(feature = "json"))]
{
write!(f, "<json>")
}
}
}
#[cfg(feature = "json")]
pub fn json_parse(s: &str) -> Result<Json, JsonParseError> {
Json::parse(s)
}
#[cfg(feature = "json")]
pub fn json_parse_bytes(bytes: &[u8]) -> Result<Json, JsonParseError> {
Json::parse_bytes(bytes)
}
#[cfg(feature = "json")]
pub fn json_stringify(json: &Json) -> AzString {
json.to_string()
}
#[cfg(feature = "json")]
pub fn json_stringify_pretty(json: &Json) -> AzString {
json.to_string_pretty()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[cfg(feature = "json")]
fn test_parse_null() {
let json = Json::parse("null").unwrap();
assert!(json.is_null());
}
#[test]
#[cfg(feature = "json")]
fn test_parse_bool() {
let json_true = Json::parse("true").unwrap();
assert_eq!(json_true.as_bool(), Some(true));
let json_false = Json::parse("false").unwrap();
assert_eq!(json_false.as_bool(), Some(false));
}
#[test]
#[cfg(feature = "json")]
fn test_parse_number() {
let json = Json::parse("42.5").unwrap();
assert_eq!(json.as_number(), Some(42.5));
let json_int = Json::parse("100").unwrap();
assert_eq!(json_int.as_i64(), Some(100));
}
#[test]
#[cfg(feature = "json")]
fn test_parse_string() {
let json = Json::parse("\"hello world\"").unwrap();
assert_eq!(json.as_string(), Some("hello world"));
}
#[test]
#[cfg(feature = "json")]
fn test_parse_array() {
let json = Json::parse("[1, 2, 3]").unwrap();
assert!(json.is_array());
assert_eq!(json.len(), 3);
let first = json.get_index(0).unwrap();
assert_eq!(first.as_number(), Some(1.0));
}
#[test]
#[cfg(feature = "json")]
fn test_parse_object() {
let json = Json::parse(r#"{"name": "test", "value": 42}"#).unwrap();
assert!(json.is_object());
assert_eq!(json.len(), 2);
let name = json.get_key("name").unwrap();
assert_eq!(name.as_string(), Some("test"));
let value = json.get_key("value").unwrap();
assert_eq!(value.as_number(), Some(42.0));
}
#[test]
#[cfg(feature = "json")]
fn test_nested() {
let json = Json::parse(r#"{"items": [1, 2, {"nested": true}]}"#).unwrap();
let items = json.get_key("items").unwrap();
assert!(items.is_array());
let nested_obj = items.get_index(2).unwrap();
let nested = nested_obj.get_key("nested").unwrap();
assert_eq!(nested.as_bool(), Some(true));
}
#[test]
#[cfg(feature = "json")]
fn test_parse_error() {
let result = Json::parse("{ invalid }");
assert!(result.is_err());
let err = result.unwrap_err();
assert!(err.line > 0);
}
}
use azul_core::refany::RefAny;
#[derive(Debug, Clone)]
#[repr(C, u8)]
pub enum ResultRefAnyString {
Ok(RefAny),
Err(AzString),
}
impl_option!(ResultRefAnyString, OptionResultRefAnyString, copy = false, [Debug, Clone]);
impl ResultRefAnyString {
pub fn is_ok(&self) -> bool {
matches!(self, ResultRefAnyString::Ok(_))
}
pub fn is_err(&self) -> bool {
matches!(self, ResultRefAnyString::Err(_))
}
pub fn ok(self) -> Option<RefAny> {
match self {
ResultRefAnyString::Ok(r) => Some(r),
ResultRefAnyString::Err(_) => None,
}
}
pub fn err(self) -> Option<AzString> {
match self {
ResultRefAnyString::Ok(_) => None,
ResultRefAnyString::Err(e) => Some(e),
}
}
}
pub type RefAnySerializeFnType = extern "C" fn(RefAny) -> Json;
pub type RefAnyDeserializeFnType = extern "C" fn(Json) -> ResultRefAnyString;
#[cfg(feature = "json")]
pub fn serialize_refany_to_json(refany: &RefAny) -> Option<Json> {
let serialize_fn = refany.get_serialize_fn();
if serialize_fn == 0 {
return None;
}
let func: RefAnySerializeFnType = unsafe {
core::mem::transmute(serialize_fn)
};
let json = func(refany.clone());
if json.is_null() {
None
} else {
Some(json)
}
}
#[cfg(feature = "json")]
pub fn deserialize_refany_from_json(
json: Json,
deserialize_fn: usize
) -> Result<RefAny, String> {
if deserialize_fn == 0 {
return Err("Type does not support JSON deserialization".to_string());
}
let func: RefAnyDeserializeFnType = unsafe {
core::mem::transmute(deserialize_fn)
};
match func(json) {
ResultRefAnyString::Ok(refany) => Ok(refany),
ResultRefAnyString::Err(msg) => Err(msg.as_str().to_string()),
}
}
impl From<Result<RefAny, String>> for ResultRefAnyString {
fn from(result: Result<RefAny, String>) -> Self {
match result {
Ok(refany) => ResultRefAnyString::Ok(refany),
Err(msg) => ResultRefAnyString::Err(AzString::from(msg)),
}
}
}
impl ResultRefAnyString {
pub fn ok_result(refany: RefAny) -> Self {
ResultRefAnyString::Ok(refany)
}
pub fn err_result(message: AzString) -> Self {
ResultRefAnyString::Err(message)
}
}
#[cfg(feature = "json")]
pub fn refany_serialize_to_json(refany: &RefAny) -> OptionJson {
match serialize_refany_to_json(refany) {
Some(json) => OptionJson::Some(json),
None => OptionJson::None,
}
}
impl Json {
#[cfg(feature = "json")]
pub fn deserialize_to_refany(self, deserialize_fn: usize) -> ResultRefAnyString {
deserialize_refany_from_json(self, deserialize_fn).into()
}
}