use crate::{Limits, native};
use alloc::{string::ToString, vec::Vec};
use serde::{Deserialize, Serialize};
pub use ic_wire_derive::{query, update};
pub const DEFAULT_REQUEST_LIMITS: Limits = Limits {
bytes: 64 * 1024,
allocation: 8 * 1024 * 1024,
nodes: 65_536,
depth: 32,
};
pub const DEFAULT_RESPONSE_LIMITS: Limits = DEFAULT_REQUEST_LIMITS;
pub struct Contract<Request, Response> {
pub name: &'static str,
pub mode: &'static str,
pub id: u64,
pub request: Limits,
pub response: Limits,
types: core::marker::PhantomData<fn(Request) -> Response>,
}
impl<Request, Response> Contract<Request, Response> {
pub fn admit_request(&self) {
admit_frame(self.id, self.request);
}
#[doc(hidden)]
pub const fn new(
name: &'static str,
mode: &'static str,
id: u64,
request: Limits,
response: Limits,
) -> Self {
Self {
name,
mode,
id,
request,
response,
types: core::marker::PhantomData,
}
}
}
#[cfg(all(feature = "typescript", not(target_family = "wasm")))]
impl<Request: crate::typescript::Wire, Response: crate::typescript::Wire>
Contract<Request, Response>
{
pub fn request_schema(&self) -> Result<serde_json::Value, crate::typescript::GenerationError> {
crate::typescript::native_schema::<Request>()
}
pub fn response_schema(&self) -> Result<serde_json::Value, crate::typescript::GenerationError> {
crate::typescript::native_schema::<Response>()
}
}
#[doc(hidden)]
pub mod __private {
pub use ic_platform::cdk;
}
pub fn admit_request(limits: Limits) {
admit_request_len(limits);
}
fn admit_request_len(limits: Limits) -> usize {
let length = ic_platform::ic0::msg_arg_data_size();
if length > limits.bytes {
ic_platform::cdk::api::trap("Wire request exceeds byte allowance");
}
length
}
#[cfg_attr(target_arch = "wasm32", inline(never))]
fn admit_frame(id: u64, limits: Limits) {
let length = admit_request_len(limits);
if length < crate::contract::HEADER {
trap_error(crate::Error::Malformed);
}
let mut header = [0; crate::contract::HEADER];
ic_platform::ic0::msg_arg_data_copy(&mut header, 0);
crate::contract::payload(id, 0, &header).unwrap_or_else(|error| trap_error(error));
}
pub fn decode_request<'de, T: Deserialize<'de>>(bytes: &'de [u8], id: u64, limits: Limits) -> T {
native::decode_request(id, bytes, limits).unwrap_or_else(|error| trap_error(error))
}
pub fn encode_response<T: Serialize + ?Sized>(value: &T, id: u64, limits: Limits) -> Vec<u8> {
native::encode_response(id, value, limits).unwrap_or_else(|error| trap_error(error))
}
#[cold]
#[inline(never)]
fn trap_error(error: crate::Error) -> ! {
ic_platform::cdk::api::trap(error.to_string())
}