1use std::{
2 borrow::{Borrow, Cow},
3 fmt::Display,
4 fs::File,
5 io::Read,
6 ops::Deref,
7 path::Path,
8};
9
10use blake3::{traits::digest::Digest, Hasher as Blake3};
11use serde::{Deserialize, Deserializer, Serialize};
12use serde_with::serde_as;
13
14use crate::generated::client_request::{
15 DelegateKey as FbsDelegateKey, InboundDelegateMsg as FbsInboundDelegateMsg,
16 InboundDelegateMsgType,
17};
18
19use crate::common_generated::common::SecretsId as FbsSecretsId;
20
21use crate::client_api::{TryFromFbs, WsApiError};
22use crate::prelude::{ContractInstanceId, WrappedState, CONTRACT_KEY_SIZE};
23use crate::{code_hash::CodeHash, prelude::Parameters};
24
25const DELEGATE_HASH_LENGTH: usize = 32;
26
27#[derive(Clone, Debug, Serialize, Deserialize)]
28pub struct Delegate<'a> {
29 #[serde(borrow)]
30 parameters: Parameters<'a>,
31 #[serde(borrow)]
32 pub data: DelegateCode<'a>,
33 key: DelegateKey,
34}
35
36impl Delegate<'_> {
37 pub fn key(&self) -> &DelegateKey {
38 &self.key
39 }
40
41 pub fn code(&self) -> &DelegateCode<'_> {
42 &self.data
43 }
44
45 pub fn code_hash(&self) -> &CodeHash {
46 &self.data.code_hash
47 }
48
49 pub fn params(&self) -> &Parameters<'_> {
50 &self.parameters
51 }
52
53 pub fn into_owned(self) -> Delegate<'static> {
54 Delegate {
55 parameters: self.parameters.into_owned(),
56 data: self.data.into_owned(),
57 key: self.key,
58 }
59 }
60
61 pub fn size(&self) -> usize {
62 self.parameters.size() + self.data.size()
63 }
64
65 pub(crate) fn deserialize_delegate<'de, D>(deser: D) -> Result<Delegate<'static>, D::Error>
66 where
67 D: Deserializer<'de>,
68 {
69 let data: Delegate<'de> = Deserialize::deserialize(deser)?;
70 Ok(data.into_owned())
71 }
72}
73
74impl PartialEq for Delegate<'_> {
75 fn eq(&self, other: &Self) -> bool {
76 self.key == other.key
77 }
78}
79
80impl Eq for Delegate<'_> {}
81
82impl<'a> From<(&DelegateCode<'a>, &Parameters<'a>)> for Delegate<'a> {
83 fn from((data, parameters): (&DelegateCode<'a>, &Parameters<'a>)) -> Self {
84 Self {
85 key: DelegateKey::from_params_and_code(parameters, data),
86 parameters: parameters.clone(),
87 data: data.clone(),
88 }
89 }
90}
91
92#[derive(Debug, Serialize, Deserialize, Clone)]
94#[serde_as]
95pub struct DelegateCode<'a> {
96 #[serde_as(as = "serde_with::Bytes")]
97 #[serde(borrow)]
98 pub(crate) data: Cow<'a, [u8]>,
99 pub(crate) code_hash: CodeHash,
101}
102
103impl DelegateCode<'static> {
104 pub fn load_raw(path: &Path) -> Result<Self, std::io::Error> {
106 let contract_data = Self::load_bytes(path)?;
107 Ok(DelegateCode::from(contract_data))
108 }
109
110 pub(crate) fn load_bytes(path: &Path) -> Result<Vec<u8>, std::io::Error> {
111 let mut contract_file = File::open(path)?;
112 let mut contract_data = if let Ok(md) = contract_file.metadata() {
113 Vec::with_capacity(md.len() as usize)
114 } else {
115 Vec::new()
116 };
117 contract_file.read_to_end(&mut contract_data)?;
118 Ok(contract_data)
119 }
120}
121
122impl DelegateCode<'_> {
123 pub fn hash(&self) -> &CodeHash {
125 &self.code_hash
126 }
127
128 pub fn hash_str(&self) -> String {
130 Self::encode_hash(&self.code_hash.0)
131 }
132
133 pub fn data(&self) -> &[u8] {
135 &self.data
136 }
137
138 pub fn encode_hash(hash: &[u8; DELEGATE_HASH_LENGTH]) -> String {
140 bs58::encode(hash)
141 .with_alphabet(bs58::Alphabet::BITCOIN)
142 .into_string()
143 }
144
145 pub fn into_owned(self) -> DelegateCode<'static> {
146 DelegateCode {
147 code_hash: self.code_hash,
148 data: Cow::from(self.data.into_owned()),
149 }
150 }
151
152 pub fn size(&self) -> usize {
153 self.data.len()
154 }
155}
156
157impl PartialEq for DelegateCode<'_> {
158 fn eq(&self, other: &Self) -> bool {
159 self.code_hash == other.code_hash
160 }
161}
162
163impl Eq for DelegateCode<'_> {}
164
165impl AsRef<[u8]> for DelegateCode<'_> {
166 fn as_ref(&self) -> &[u8] {
167 self.data.borrow()
168 }
169}
170
171impl From<Vec<u8>> for DelegateCode<'static> {
172 fn from(data: Vec<u8>) -> Self {
173 let key = CodeHash::from_code(data.as_slice());
174 DelegateCode {
175 data: Cow::from(data),
176 code_hash: key,
177 }
178 }
179}
180
181impl<'a> From<&'a [u8]> for DelegateCode<'a> {
182 fn from(code: &'a [u8]) -> Self {
183 let key = CodeHash::from_code(code);
184 DelegateCode {
185 data: Cow::from(code),
186 code_hash: key,
187 }
188 }
189}
190
191#[serde_as]
192#[derive(Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)]
193pub struct DelegateKey {
194 #[serde_as(as = "[_; DELEGATE_HASH_LENGTH]")]
195 key: [u8; DELEGATE_HASH_LENGTH],
196 code_hash: CodeHash,
197}
198
199impl From<DelegateKey> for SecretsId {
200 fn from(key: DelegateKey) -> SecretsId {
201 SecretsId {
202 hash: key.key,
203 key: vec![],
204 }
205 }
206}
207
208impl DelegateKey {
209 pub const fn new(key: [u8; DELEGATE_HASH_LENGTH], code_hash: CodeHash) -> Self {
210 Self { key, code_hash }
211 }
212
213 fn from_params_and_code<'a>(
214 params: impl Borrow<Parameters<'a>>,
215 wasm_code: impl Borrow<DelegateCode<'a>>,
216 ) -> Self {
217 let code = wasm_code.borrow();
218 let key = generate_id(params.borrow(), code);
219 Self {
220 key,
221 code_hash: *code.hash(),
222 }
223 }
224
225 pub fn encode(&self) -> String {
226 bs58::encode(self.key)
227 .with_alphabet(bs58::Alphabet::BITCOIN)
228 .into_string()
229 }
230
231 pub fn code_hash(&self) -> &CodeHash {
232 &self.code_hash
233 }
234
235 pub fn bytes(&self) -> &[u8] {
236 self.key.as_ref()
237 }
238
239 pub fn from_params(
240 code_hash: impl Into<String>,
241 parameters: &Parameters,
242 ) -> Result<Self, bs58::decode::Error> {
243 let mut code_key = [0; DELEGATE_HASH_LENGTH];
244 bs58::decode(code_hash.into())
245 .with_alphabet(bs58::Alphabet::BITCOIN)
246 .onto(&mut code_key)?;
247 let mut hasher = Blake3::new();
248 hasher.update(code_key.as_slice());
249 hasher.update(parameters.as_ref());
250 let full_key_arr = hasher.finalize();
251
252 debug_assert_eq!(full_key_arr[..].len(), DELEGATE_HASH_LENGTH);
253 let mut key = [0; DELEGATE_HASH_LENGTH];
254 key.copy_from_slice(&full_key_arr);
255
256 Ok(Self {
257 key,
258 code_hash: CodeHash(code_key),
259 })
260 }
261}
262
263impl Deref for DelegateKey {
264 type Target = [u8; DELEGATE_HASH_LENGTH];
265
266 fn deref(&self) -> &Self::Target {
267 &self.key
268 }
269}
270
271impl Display for DelegateKey {
272 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
273 write!(f, "{}", self.encode())
274 }
275}
276
277impl<'a> TryFromFbs<&FbsDelegateKey<'a>> for DelegateKey {
278 fn try_decode_fbs(key: &FbsDelegateKey<'a>) -> Result<Self, WsApiError> {
279 let mut key_bytes = [0; DELEGATE_HASH_LENGTH];
280 key_bytes.copy_from_slice(key.key().bytes().iter().as_ref());
281 Ok(DelegateKey {
282 key: key_bytes,
283 code_hash: CodeHash::from_code(key.code_hash().bytes()),
284 })
285 }
286}
287
288#[derive(Debug, thiserror::Error, Serialize, Deserialize)]
290pub enum DelegateError {
291 #[error("de/serialization error: {0}")]
292 Deser(String),
293 #[error("{0}")]
294 Other(String),
295}
296
297fn generate_id<'a>(
298 parameters: &Parameters<'a>,
299 code_data: &DelegateCode<'a>,
300) -> [u8; DELEGATE_HASH_LENGTH] {
301 let contract_hash = code_data.hash();
302
303 let mut hasher = Blake3::new();
304 hasher.update(contract_hash.0.as_slice());
305 hasher.update(parameters.as_ref());
306 let full_key_arr = hasher.finalize();
307
308 debug_assert_eq!(full_key_arr[..].len(), DELEGATE_HASH_LENGTH);
309 let mut key = [0; DELEGATE_HASH_LENGTH];
310 key.copy_from_slice(&full_key_arr);
311 key
312}
313
314#[serde_as]
315#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq)]
316pub struct SecretsId {
317 #[serde_as(as = "serde_with::Bytes")]
318 key: Vec<u8>,
319 #[serde_as(as = "[_; 32]")]
320 hash: [u8; 32],
321}
322
323impl SecretsId {
324 pub fn new(key: Vec<u8>) -> Self {
325 let mut hasher = Blake3::new();
326 hasher.update(&key);
327 let hashed = hasher.finalize();
328 let mut hash = [0; 32];
329 hash.copy_from_slice(&hashed);
330 Self { key, hash }
331 }
332
333 pub fn encode(&self) -> String {
334 bs58::encode(self.hash)
335 .with_alphabet(bs58::Alphabet::BITCOIN)
336 .into_string()
337 }
338
339 pub fn hash(&self) -> &[u8; 32] {
340 &self.hash
341 }
342 pub fn key(&self) -> &[u8] {
343 self.key.as_slice()
344 }
345}
346
347impl Display for SecretsId {
348 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
349 write!(f, "{}", self.encode())
350 }
351}
352
353impl<'a> TryFromFbs<&FbsSecretsId<'a>> for SecretsId {
354 fn try_decode_fbs(key: &FbsSecretsId<'a>) -> Result<Self, WsApiError> {
355 let mut key_hash = [0; 32];
356 key_hash.copy_from_slice(key.hash().bytes().iter().as_ref());
357 Ok(SecretsId {
358 key: key.key().bytes().to_vec(),
359 hash: key_hash,
360 })
361 }
362}
363
364pub trait DelegateInterface {
409 fn process(
420 ctx: &mut crate::delegate_host::DelegateCtx,
421 parameters: Parameters<'static>,
422 attested: Option<&'static [u8]>,
423 message: InboundDelegateMsg,
424 ) -> Result<Vec<OutboundDelegateMsg>, DelegateError>;
425}
426
427#[serde_as]
428#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
429pub struct DelegateContext(#[serde_as(as = "serde_with::Bytes")] Vec<u8>);
430
431impl DelegateContext {
432 pub const MAX_SIZE: usize = 4096 * 10 * 10;
433
434 pub fn new(bytes: Vec<u8>) -> Self {
435 assert!(bytes.len() < Self::MAX_SIZE);
436 Self(bytes)
437 }
438
439 pub fn append(&mut self, bytes: &mut Vec<u8>) {
440 assert!(self.0.len() + bytes.len() < Self::MAX_SIZE);
441 self.0.append(bytes)
442 }
443
444 pub fn replace(&mut self, bytes: Vec<u8>) {
445 assert!(bytes.len() < Self::MAX_SIZE);
446 let _ = std::mem::replace(&mut self.0, bytes);
447 }
448}
449
450impl AsRef<[u8]> for DelegateContext {
451 fn as_ref(&self) -> &[u8] {
452 &self.0
453 }
454}
455
456#[derive(Serialize, Deserialize, Debug, Clone)]
457pub enum InboundDelegateMsg<'a> {
458 ApplicationMessage(ApplicationMessage),
459 UserResponse(#[serde(borrow)] UserInputResponse<'a>),
460 GetContractResponse(GetContractResponse),
461}
462
463impl InboundDelegateMsg<'_> {
464 pub fn into_owned(self) -> InboundDelegateMsg<'static> {
465 match self {
466 InboundDelegateMsg::ApplicationMessage(r) => InboundDelegateMsg::ApplicationMessage(r),
467 InboundDelegateMsg::UserResponse(r) => InboundDelegateMsg::UserResponse(r.into_owned()),
468 InboundDelegateMsg::GetContractResponse(r) => {
469 InboundDelegateMsg::GetContractResponse(r)
470 }
471 }
472 }
473
474 pub fn get_context(&self) -> Option<&DelegateContext> {
475 match self {
476 InboundDelegateMsg::ApplicationMessage(ApplicationMessage { context, .. }) => {
477 Some(context)
478 }
479 InboundDelegateMsg::GetContractResponse(GetContractResponse { context, .. }) => {
480 Some(context)
481 }
482 _ => None,
483 }
484 }
485
486 pub fn get_mut_context(&mut self) -> Option<&mut DelegateContext> {
487 match self {
488 InboundDelegateMsg::ApplicationMessage(ApplicationMessage { context, .. }) => {
489 Some(context)
490 }
491 InboundDelegateMsg::GetContractResponse(GetContractResponse { context, .. }) => {
492 Some(context)
493 }
494 _ => None,
495 }
496 }
497}
498
499impl From<ApplicationMessage> for InboundDelegateMsg<'_> {
500 fn from(value: ApplicationMessage) -> Self {
501 Self::ApplicationMessage(value)
502 }
503}
504
505impl<'a> TryFromFbs<&FbsInboundDelegateMsg<'a>> for InboundDelegateMsg<'a> {
506 fn try_decode_fbs(msg: &FbsInboundDelegateMsg<'a>) -> Result<Self, WsApiError> {
507 match msg.inbound_type() {
508 InboundDelegateMsgType::common_ApplicationMessage => {
509 let app_msg = msg.inbound_as_common_application_message().unwrap();
510 let mut instance_key_bytes = [0; CONTRACT_KEY_SIZE];
511 instance_key_bytes
512 .copy_from_slice(app_msg.app().data().bytes().to_vec().as_slice());
513 let app_msg = ApplicationMessage {
514 app: ContractInstanceId::new(instance_key_bytes),
515 payload: app_msg.payload().bytes().to_vec(),
516 context: DelegateContext::new(app_msg.context().bytes().to_vec()),
517 processed: app_msg.processed(),
518 };
519 Ok(InboundDelegateMsg::ApplicationMessage(app_msg))
520 }
521 InboundDelegateMsgType::UserInputResponse => {
522 let user_response = msg.inbound_as_user_input_response().unwrap();
523 let user_response = UserInputResponse {
524 request_id: user_response.request_id(),
525 response: ClientResponse::new(user_response.response().data().bytes().to_vec()),
526 context: DelegateContext::new(
527 user_response.delegate_context().bytes().to_vec(),
528 ),
529 };
530 Ok(InboundDelegateMsg::UserResponse(user_response))
531 }
532 _ => unreachable!("invalid inbound delegate message type"),
533 }
534 }
535}
536
537#[non_exhaustive]
538#[derive(Serialize, Deserialize, Debug, Clone)]
539pub struct ApplicationMessage {
540 pub app: ContractInstanceId,
541 pub payload: Vec<u8>,
542 pub context: DelegateContext,
543 pub processed: bool,
544}
545
546impl ApplicationMessage {
547 pub fn new(app: ContractInstanceId, payload: Vec<u8>) -> Self {
548 Self {
549 app,
550 payload,
551 context: DelegateContext::default(),
552 processed: false,
553 }
554 }
555
556 pub fn with_context(mut self, context: DelegateContext) -> Self {
557 self.context = context;
558 self
559 }
560
561 pub fn processed(mut self, p: bool) -> Self {
562 self.processed = p;
563 self
564 }
565}
566
567#[derive(Serialize, Deserialize, Debug, Clone)]
568pub struct UserInputResponse<'a> {
569 pub request_id: u32,
570 #[serde(borrow)]
571 pub response: ClientResponse<'a>,
572 pub context: DelegateContext,
573}
574
575impl UserInputResponse<'_> {
576 pub fn into_owned(self) -> UserInputResponse<'static> {
577 UserInputResponse {
578 request_id: self.request_id,
579 response: self.response.into_owned(),
580 context: self.context,
581 }
582 }
583}
584
585#[derive(Serialize, Deserialize, Debug, Clone)]
586pub enum OutboundDelegateMsg {
587 ApplicationMessage(ApplicationMessage),
589 RequestUserInput(
590 #[serde(deserialize_with = "OutboundDelegateMsg::deser_user_input_req")]
591 UserInputRequest<'static>,
592 ),
593 ContextUpdated(DelegateContext),
595 GetContractRequest(GetContractRequest),
596}
597
598impl From<ApplicationMessage> for OutboundDelegateMsg {
599 fn from(req: ApplicationMessage) -> Self {
600 Self::ApplicationMessage(req)
601 }
602}
603
604impl From<GetContractRequest> for OutboundDelegateMsg {
605 fn from(req: GetContractRequest) -> Self {
606 Self::GetContractRequest(req)
607 }
608}
609
610impl OutboundDelegateMsg {
611 fn deser_user_input_req<'de, D>(deser: D) -> Result<UserInputRequest<'static>, D::Error>
612 where
613 D: serde::Deserializer<'de>,
614 {
615 let value = <UserInputRequest<'de> as Deserialize>::deserialize(deser)?;
616 Ok(value.into_owned())
617 }
618
619 pub fn processed(&self) -> bool {
620 match self {
621 OutboundDelegateMsg::ApplicationMessage(msg) => msg.processed,
622 OutboundDelegateMsg::GetContractRequest(msg) => msg.processed,
623 OutboundDelegateMsg::RequestUserInput(_) => true,
624 OutboundDelegateMsg::ContextUpdated(_) => true,
625 }
626 }
627
628 pub fn get_context(&self) -> Option<&DelegateContext> {
629 match self {
630 OutboundDelegateMsg::ApplicationMessage(ApplicationMessage { context, .. }) => {
631 Some(context)
632 }
633 OutboundDelegateMsg::GetContractRequest(GetContractRequest { context, .. }) => {
634 Some(context)
635 }
636 _ => None,
637 }
638 }
639
640 pub fn get_mut_context(&mut self) -> Option<&mut DelegateContext> {
641 match self {
642 OutboundDelegateMsg::ApplicationMessage(ApplicationMessage { context, .. }) => {
643 Some(context)
644 }
645 OutboundDelegateMsg::GetContractRequest(GetContractRequest { context, .. }) => {
646 Some(context)
647 }
648 _ => None,
649 }
650 }
651}
652
653#[derive(Serialize, Deserialize, Debug, Clone)]
655pub struct GetContractRequest {
656 pub contract_id: ContractInstanceId,
657 pub context: DelegateContext,
658 pub processed: bool,
659}
660
661impl GetContractRequest {
662 pub fn new(contract_id: ContractInstanceId) -> Self {
663 Self {
664 contract_id,
665 context: Default::default(),
666 processed: false,
667 }
668 }
669}
670
671#[derive(Serialize, Deserialize, Debug, Clone)]
673pub struct GetContractResponse {
674 pub contract_id: ContractInstanceId,
675 pub state: Option<WrappedState>,
677 pub context: DelegateContext,
678}
679
680#[serde_as]
681#[derive(Serialize, Deserialize, Debug, Clone)]
682pub struct NotificationMessage<'a>(
683 #[serde_as(as = "serde_with::Bytes")]
684 #[serde(borrow)]
685 Cow<'a, [u8]>,
686);
687
688impl TryFrom<&serde_json::Value> for NotificationMessage<'static> {
689 type Error = ();
690
691 fn try_from(json: &serde_json::Value) -> Result<NotificationMessage<'static>, ()> {
692 let bytes = serde_json::to_vec(json).unwrap();
694 Ok(Self(Cow::Owned(bytes)))
695 }
696}
697
698impl NotificationMessage<'_> {
699 pub fn into_owned(self) -> NotificationMessage<'static> {
700 NotificationMessage(self.0.into_owned().into())
701 }
702 pub fn bytes(&self) -> &[u8] {
703 self.0.as_ref()
704 }
705}
706
707#[serde_as]
708#[derive(Serialize, Deserialize, Debug, Clone)]
709pub struct ClientResponse<'a>(
710 #[serde_as(as = "serde_with::Bytes")]
711 #[serde(borrow)]
712 Cow<'a, [u8]>,
713);
714
715impl Deref for ClientResponse<'_> {
716 type Target = [u8];
717
718 fn deref(&self) -> &Self::Target {
719 &self.0
720 }
721}
722
723impl ClientResponse<'_> {
724 pub fn new(response: Vec<u8>) -> Self {
725 Self(response.into())
726 }
727 pub fn into_owned(self) -> ClientResponse<'static> {
728 ClientResponse(self.0.into_owned().into())
729 }
730 pub fn bytes(&self) -> &[u8] {
731 self.0.as_ref()
732 }
733}
734
735#[derive(Serialize, Deserialize, Debug, Clone)]
736pub struct UserInputRequest<'a> {
737 pub request_id: u32,
738 #[serde(borrow)]
739 pub message: NotificationMessage<'a>,
741 pub responses: Vec<ClientResponse<'a>>,
743}
744
745impl UserInputRequest<'_> {
746 pub fn into_owned(self) -> UserInputRequest<'static> {
747 UserInputRequest {
748 request_id: self.request_id,
749 message: self.message.into_owned(),
750 responses: self.responses.into_iter().map(|r| r.into_owned()).collect(),
751 }
752 }
753}
754
755#[doc(hidden)]
756pub(crate) mod wasm_interface {
757 use super::*;
760 use crate::memory::WasmLinearMem;
761
762 #[repr(C)]
763 #[derive(Debug, Clone, Copy)]
764 pub struct DelegateInterfaceResult {
765 ptr: i64,
766 size: u32,
767 }
768
769 impl DelegateInterfaceResult {
770 pub unsafe fn from_raw(ptr: i64, mem: &WasmLinearMem) -> Self {
771 let result = Box::leak(Box::from_raw(crate::memory::buf::compute_ptr(
772 ptr as *mut Self,
773 mem,
774 )));
775 #[cfg(feature = "trace")]
776 {
777 tracing::trace!(
778 "got FFI result @ {ptr} ({:p}) -> {result:?}",
779 ptr as *mut Self
780 );
781 }
782 *result
783 }
784
785 #[cfg(feature = "contract")]
786 pub fn into_raw(self) -> i64 {
787 #[cfg(feature = "trace")]
788 {
789 tracing::trace!("returning FFI -> {self:?}");
790 }
791 let ptr = Box::into_raw(Box::new(self));
792 #[cfg(feature = "trace")]
793 {
794 tracing::trace!("FFI result ptr: {ptr:p} ({}i64)", ptr as i64);
795 }
796 ptr as _
797 }
798
799 pub unsafe fn unwrap(
800 self,
801 mem: WasmLinearMem,
802 ) -> Result<Vec<OutboundDelegateMsg>, DelegateError> {
803 let ptr = crate::memory::buf::compute_ptr(self.ptr as *mut u8, &mem);
804 let serialized = std::slice::from_raw_parts(ptr as *const u8, self.size as _);
805 let value: Result<Vec<OutboundDelegateMsg>, DelegateError> =
806 bincode::deserialize(serialized)
807 .map_err(|e| DelegateError::Other(format!("{e}")))?;
808 #[cfg(feature = "trace")]
809 {
810 tracing::trace!(
811 "got result through FFI; addr: {:p} ({}i64, mapped: {ptr:p})
812 serialized: {serialized:?}
813 value: {value:?}",
814 self.ptr as *mut u8,
815 self.ptr
816 );
817 }
818 value
819 }
820 }
821
822 impl From<Result<Vec<OutboundDelegateMsg>, DelegateError>> for DelegateInterfaceResult {
823 fn from(value: Result<Vec<OutboundDelegateMsg>, DelegateError>) -> Self {
824 let serialized = bincode::serialize(&value).unwrap();
825 let size = serialized.len() as _;
826 let ptr = serialized.as_ptr();
827 #[cfg(feature = "trace")]
828 {
829 tracing::trace!(
830 "sending result through FFI; addr: {ptr:p} ({}),\n serialized: {serialized:?}\n value: {value:?}",
831 ptr as i64
832 );
833 }
834 std::mem::forget(serialized);
835 Self {
836 ptr: ptr as i64,
837 size,
838 }
839 }
840 }
841}