/// this returns a value to the host in an exported function
pub fn send[T: ToJson](data: T) -> Unit {
  @host.output_json_value(data.to_json())
}

/// Allocates a JSON object in the host memory and returns its pointer.
pub fn allocate[T: ToJson](obj: T) -> Int64 {
  //@host.log_info_str("serialized " + obj.to_json().stringify())
  @host.allocate_json_value(obj.to_json()).offset
}

/// Finds an object in the host memory and deserializes it to the given type.
pub fn deserialize[T: @json.FromJson](ptr: Int64) -> T? {
  let str = @host.find_memory(ptr).to_string()
  @host.log_info_str("deserializing " + str)
  @host.log_info_str("json " + @json.parse?(str).to_string())

  let json: Result[Json, @json.ParseError] = @json.parse?(str)
  match json {
    Ok(json) => @host.log_info_str("json found: " + json.to_string())
    Err(err) => @host.log_info_str(err.to_string())
  }

  if json.to_option().is_empty() {
    @host.log_info_str("deserialize: empty")
    return None
  }

  @json.from_json?(json.unwrap()).to_option()
}

fn getValue[T: @json.FromJson](ptr: Int64) -> T? {
  let obj = deserialize(ptr);

  if obj.is_empty() {
    @host.log_info_str("getValue: empty")
    return None
  }

  obj
}