ckb_std/syscalls/
traits.rs

1use crate::{
2    ckb_constants::{self as consts, CellField, HeaderField, InputField, Source},
3    error::SysError,
4    syscalls::internal::SpawnArgs,
5};
6use alloc::{string::String, vec::Vec};
7use core::ffi::CStr;
8
9/// This trait serves several purposes:
10///
11/// * Current ckb-std syscall implementations were written at different
12///   time with different mindsets, and accumulated throughout the years.
13///   As a result, it presents certain inconsistencies and issues. Just to
14///   name a few:
15///     + The newly introduced read syscall interprets its return values
16///       differently from old `load_*` syscalls. However they share the
17///       same return value type, which can be a source of confusion.
18///     + Some signature design could use a little work: for example, spawn
19///       sets returned process ID both in one of the mutable argument, and
20///       also in its return values. This is really duplicate information that
21///       can be revisited. In addition, the `argv` data structured, used by
22///       both spawn and exec, are passed differently in both syscalls. In
23///       hindset, maybe we don't need to expose the C style `SpawnArgs` structure
24///       in Rust APIs, but keep it as an internal data structure.
25///     + The return value of inherited_fds syscall is completely ignored,
26///       only the length of written fds is returned.
27/// * New features such as native simulators, or fuzzing require customized
28///   syscall implementations. There is no proper way we can customize a CKB
29///   script for alternative syscall implementations.
30///
31/// On the other hand, compatibility remains a consideration, it might not be
32/// possible to alter current syscall implementations, which might affect real
33/// usage.
34///
35/// This trait aims to provide a new solution, where all CKB syscalls can be
36/// provided by a single trait. It also attempts to clear and unify syscall
37/// APIs, in a clear and easy to understand fashion.
38pub trait SyscallImpls {
39    /// There are 2 ways you can implement this trait: you can either implement
40    /// this generic syscall function, where you detect the syscall by the last
41    /// `n` field, or you can implement each invididual syscall in a type-safe
42    /// way. Dummy implementations are provided for each trait method so one can
43    /// override only the needed ones.
44    fn syscall(&self, _a0: u64, _a1: u64, _a2: u64, _a3: u64, _a4: u64, _a5: u64, _n: u64) -> u64 {
45        panic!("Default syscall function is not yet implemented!")
46    }
47
48    fn syscall_load(
49        &self,
50        buf: &mut [u8],
51        offset: usize,
52        a3: u64,
53        a4: u64,
54        a5: u64,
55        syscall_num: u64,
56    ) -> IoResult {
57        let mut actual_data_len: u64 = buf.len() as u64;
58        let len_ptr: *mut u64 = &mut actual_data_len;
59        let ret = self.syscall(
60            buf.as_ptr() as u64,
61            len_ptr as u64,
62            offset as u64,
63            a3,
64            a4,
65            a5,
66            syscall_num,
67        );
68        match ret {
69            0 => {
70                if actual_data_len > buf.len() as u64 {
71                    IoResult::PartialLoaded {
72                        loaded: buf.len(),
73                        available: actual_data_len as usize,
74                    }
75                } else {
76                    IoResult::FullyLoaded(actual_data_len as usize)
77                }
78            }
79            _ => IoResult::Error(ret.try_into().unwrap()),
80        }
81    }
82
83    fn debug(&self, s: &CStr) {
84        self.syscall(s.as_ptr() as u64, 0, 0, 0, 0, 0, consts::SYS_DEBUG);
85    }
86    fn exit(&self, code: i8) -> ! {
87        self.syscall(code as u64, 0, 0, 0, 0, 0, consts::SYS_EXIT);
88        unreachable!()
89    }
90    fn load_cell(&self, buf: &mut [u8], offset: usize, index: usize, source: Source) -> IoResult {
91        self.syscall_load(
92            buf,
93            offset,
94            index as u64,
95            source as u64,
96            0,
97            consts::SYS_LOAD_CELL,
98        )
99    }
100    fn load_cell_by_field(
101        &self,
102        buf: &mut [u8],
103        offset: usize,
104        index: usize,
105        source: Source,
106        field: CellField,
107    ) -> IoResult {
108        self.syscall_load(
109            buf,
110            offset,
111            index as u64,
112            source as u64,
113            field as u64,
114            consts::SYS_LOAD_CELL_BY_FIELD,
115        )
116    }
117    fn load_cell_code(
118        &self,
119        buf_ptr: *mut u8,
120        len: usize,
121        content_offset: usize,
122        content_size: usize,
123        index: usize,
124        source: Source,
125    ) -> Result<(), Error> {
126        build_result(self.syscall(
127            buf_ptr as u64,
128            len as u64,
129            content_offset as u64,
130            content_size as u64,
131            index as u64,
132            source as u64,
133            consts::SYS_LOAD_CELL_DATA_AS_CODE,
134        ))
135    }
136    fn load_cell_data(
137        &self,
138        buf: &mut [u8],
139        offset: usize,
140        index: usize,
141        source: Source,
142    ) -> IoResult {
143        self.syscall_load(
144            buf,
145            offset,
146            index as u64,
147            source as u64,
148            0,
149            consts::SYS_LOAD_CELL_DATA,
150        )
151    }
152    fn load_header(&self, buf: &mut [u8], offset: usize, index: usize, source: Source) -> IoResult {
153        self.syscall_load(
154            buf,
155            offset,
156            index as u64,
157            source as u64,
158            0,
159            consts::SYS_LOAD_HEADER,
160        )
161    }
162    fn load_header_by_field(
163        &self,
164        buf: &mut [u8],
165        offset: usize,
166        index: usize,
167        source: Source,
168        field: HeaderField,
169    ) -> IoResult {
170        self.syscall_load(
171            buf,
172            offset,
173            index as u64,
174            source as u64,
175            field as u64,
176            consts::SYS_LOAD_HEADER_BY_FIELD,
177        )
178    }
179    fn load_input(&self, buf: &mut [u8], offset: usize, index: usize, source: Source) -> IoResult {
180        self.syscall_load(
181            buf,
182            offset,
183            index as u64,
184            source as u64,
185            0,
186            consts::SYS_LOAD_INPUT,
187        )
188    }
189    fn load_input_by_field(
190        &self,
191        buf: &mut [u8],
192        offset: usize,
193        index: usize,
194        source: Source,
195        field: InputField,
196    ) -> IoResult {
197        self.syscall_load(
198            buf,
199            offset,
200            index as u64,
201            source as u64,
202            field as u64,
203            consts::SYS_LOAD_INPUT_BY_FIELD,
204        )
205    }
206    fn load_script(&self, buf: &mut [u8], offset: usize) -> IoResult {
207        self.syscall_load(buf, offset, 0, 0, 0, consts::SYS_LOAD_SCRIPT)
208    }
209    fn load_script_hash(&self, buf: &mut [u8], offset: usize) -> IoResult {
210        self.syscall_load(buf, offset, 0, 0, 0, consts::SYS_LOAD_SCRIPT_HASH)
211    }
212    fn load_transaction(&self, buf: &mut [u8], offset: usize) -> IoResult {
213        self.syscall_load(buf, offset, 0, 0, 0, consts::SYS_LOAD_TRANSACTION)
214    }
215    fn load_tx_hash(&self, buf: &mut [u8], offset: usize) -> IoResult {
216        self.syscall_load(buf, offset, 0, 0, 0, consts::SYS_LOAD_TX_HASH)
217    }
218    fn load_witness(
219        &self,
220        buf: &mut [u8],
221        offset: usize,
222        index: usize,
223        source: Source,
224    ) -> IoResult {
225        self.syscall_load(
226            buf,
227            offset,
228            index as u64,
229            source as u64,
230            0,
231            consts::SYS_LOAD_WITNESS,
232        )
233    }
234
235    fn vm_version(&self) -> u64 {
236        self.syscall(0, 0, 0, 0, 0, 0, consts::SYS_VM_VERSION)
237    }
238    fn current_cycles(&self) -> u64 {
239        self.syscall(0, 0, 0, 0, 0, 0, consts::SYS_CURRENT_CYCLES)
240    }
241    fn exec(
242        &self,
243        index: usize,
244        source: Source,
245        place: usize,
246        bounds: usize,
247        argv: &[&CStr],
248    ) -> Result<(), Error> {
249        let argv_ptr: alloc::vec::Vec<*const i8> =
250            argv.iter().map(|e| e.as_ptr() as *const i8).collect();
251
252        build_result(self.syscall(
253            index as u64,
254            source as u64,
255            place as u64,
256            bounds as u64,
257            argv.len() as u64,
258            argv_ptr.as_ptr() as u64,
259            consts::SYS_EXEC,
260        ))
261    }
262
263    /// Spawned process ID is returned when the syscall succeeds
264    fn spawn(
265        &self,
266        index: usize,
267        source: Source,
268        place: usize,
269        bounds: usize,
270        argv: &[&CStr],
271        inherited_fds: &[u64],
272    ) -> Result<u64, Error> {
273        let mut fds_with_terminator = alloc::vec![0; inherited_fds.len() + 1];
274        fds_with_terminator[0..inherited_fds.len()].copy_from_slice(inherited_fds);
275
276        let argv_ptr: alloc::vec::Vec<*const i8> =
277            argv.iter().map(|e| e.as_ptr() as *const i8).collect();
278
279        let mut process_id = 0;
280        let mut spgs = SpawnArgs {
281            argc: argv.len() as u64,
282            argv: argv_ptr.as_ptr(),
283            process_id: &mut process_id,
284            inherited_fds: fds_with_terminator.as_ptr(),
285        };
286
287        build_result(self.syscall(
288            index as u64,
289            source as u64,
290            place as u64,
291            bounds as u64,
292            &mut spgs as *mut _ as u64,
293            0,
294            consts::SYS_SPAWN,
295        ))
296        .map(|_| process_id)
297    }
298    fn pipe(&self) -> Result<(u64, u64), Error> {
299        let mut fds: [u64; 2] = [0, 0];
300        build_result(self.syscall(fds.as_mut_ptr() as u64, 0, 0, 0, 0, 0, consts::SYS_PIPE))
301            .map(|_| (fds[0], fds[1]))
302    }
303    /// Number of available fds is returned when the syscall succeeds, which
304    /// can be bigger than the length of the passed argument `fds` slice
305    fn inherited_fds(&self, fds: &mut [u64]) -> Result<usize, Error> {
306        let mut length: u64 = fds.len() as u64;
307        build_result(self.syscall(
308            fds.as_mut_ptr() as u64,
309            &mut length as *mut _ as u64,
310            0,
311            0,
312            0,
313            0,
314            consts::SYS_INHERITED_FDS,
315        ))
316        .map(|_| length as usize)
317    }
318    /// Number of read bytes is returned when the syscall succeeds. Note
319    /// this syscall works unlike the `load_*` syscalls, it only returns
320    /// the number of bytes read to passed buffer. The syscall has no way
321    /// of knowing how many bytes are availble to read.
322    fn read(&self, fd: u64, buffer: &mut [u8]) -> Result<usize, Error> {
323        let mut length: u64 = buffer.len() as u64;
324        build_result(self.syscall(
325            fd,
326            buffer.as_mut_ptr() as u64,
327            &mut length as *mut _ as u64,
328            0,
329            0,
330            0,
331            consts::SYS_READ,
332        ))
333        .map(|_| length as usize)
334    }
335    /// Number of written bytes is returned when the syscall succeeds.
336    fn write(&self, fd: u64, buffer: &[u8]) -> Result<usize, Error> {
337        let mut length: u64 = buffer.len() as u64;
338        build_result(self.syscall(
339            fd,
340            buffer.as_ptr() as u64,
341            &mut length as *mut _ as u64,
342            0,
343            0,
344            0,
345            consts::SYS_WRITE,
346        ))
347        .map(|_| length as usize)
348    }
349    fn close(&self, fd: u64) -> Result<(), Error> {
350        build_result(self.syscall(fd, 0, 0, 0, 0, 0, consts::SYS_CLOSE))
351    }
352    /// Exit code of waited process is returned when the syscall succeeds.
353    fn wait(&self, pid: u64) -> Result<i8, Error> {
354        let mut code: u64 = u64::MAX;
355        build_result(self.syscall(
356            pid,
357            &mut code as *mut _ as u64,
358            0,
359            0,
360            0,
361            0,
362            consts::SYS_WAIT,
363        ))
364        .map(|_| code as i8)
365    }
366    fn process_id(&self) -> u64 {
367        self.syscall(0, 0, 0, 0, 0, 0, consts::SYS_PROCESS_ID)
368    }
369    fn load_block_extension(
370        &self,
371        buf: &mut [u8],
372        offset: usize,
373        index: usize,
374        source: Source,
375    ) -> IoResult {
376        self.syscall_load(
377            buf,
378            offset,
379            index as u64,
380            source as u64,
381            0,
382            consts::SYS_LOAD_BLOCK_EXTENSION,
383        )
384    }
385
386    fn debug_s(&self, mut s: String) {
387        s.push('\0');
388        let bytes = s.into_bytes();
389        let c_str = CStr::from_bytes_until_nul(&bytes).unwrap();
390        self.debug(c_str)
391    }
392}
393
394/// This is the inverse of DefaultSyscallImpls: given a general syscall function,
395/// we map the syscalls to a SyscallImpls trait impl. This way we are taking care
396/// of the unsafe part for you, where in Rust you can just deal with SyscallImpls.
397pub fn syscall_to_impls<S: SyscallImpls + ?Sized>(
398    impls: &S,
399    n: u64,
400    a0: u64,
401    a1: u64,
402    a2: u64,
403    a3: u64,
404    a4: u64,
405    a5: u64,
406) -> u64 {
407    match n {
408        consts::SYS_DEBUG => {
409            impls.debug(unsafe { CStr::from_ptr(a0 as *const _) });
410            0
411        }
412        consts::SYS_EXIT => impls.exit(a0 as i8),
413        consts::SYS_LOAD_CELL => load_to_impls(a0, a1, |buf| {
414            let source: Source = a4.try_into().expect("parse source");
415            impls.load_cell(buf, a2 as usize, a3 as usize, source)
416        }),
417        consts::SYS_LOAD_CELL_BY_FIELD => load_to_impls(a0, a1, |buf| {
418            let source: Source = a4.try_into().expect("parse source");
419            let field: CellField = a5.try_into().expect("parse cell field");
420            impls.load_cell_by_field(buf, a2 as usize, a3 as usize, source, field)
421        }),
422        consts::SYS_LOAD_CELL_DATA_AS_CODE => {
423            let source: Source = a5.try_into().expect("parse source");
424            match impls.load_cell_code(
425                a0 as *mut u8,
426                a1 as usize,
427                a2 as usize,
428                a3 as usize,
429                a4 as usize,
430                source,
431            ) {
432                Ok(()) => 0,
433                Err(e) => e.into(),
434            }
435        }
436        consts::SYS_LOAD_CELL_DATA => load_to_impls(a0, a1, |buf| {
437            let source: Source = a4.try_into().expect("parse source");
438            impls.load_cell_data(buf, a2 as usize, a3 as usize, source)
439        }),
440        consts::SYS_LOAD_HEADER => load_to_impls(a0, a1, |buf| {
441            let source: Source = a4.try_into().expect("parse source");
442            impls.load_header(buf, a2 as usize, a3 as usize, source)
443        }),
444        consts::SYS_LOAD_HEADER_BY_FIELD => load_to_impls(a0, a1, |buf| {
445            let source: Source = a4.try_into().expect("parse source");
446            let field: HeaderField = a5.try_into().expect("parse header field");
447            impls.load_header_by_field(buf, a2 as usize, a3 as usize, source, field)
448        }),
449        consts::SYS_LOAD_INPUT => load_to_impls(a0, a1, |buf| {
450            let source: Source = a4.try_into().expect("parse source");
451            impls.load_input(buf, a2 as usize, a3 as usize, source)
452        }),
453        consts::SYS_LOAD_INPUT_BY_FIELD => load_to_impls(a0, a1, |buf| {
454            let source: Source = a4.try_into().expect("parse source");
455            let field: InputField = a5.try_into().expect("parse input field");
456            impls.load_input_by_field(buf, a2 as usize, a3 as usize, source, field)
457        }),
458        consts::SYS_LOAD_SCRIPT => load_to_impls(a0, a1, |buf| impls.load_script(buf, a2 as usize)),
459        consts::SYS_LOAD_SCRIPT_HASH => {
460            load_to_impls(a0, a1, |buf| impls.load_script_hash(buf, a2 as usize))
461        }
462        consts::SYS_LOAD_TRANSACTION => {
463            load_to_impls(a0, a1, |buf| impls.load_transaction(buf, a2 as usize))
464        }
465        consts::SYS_LOAD_TX_HASH => {
466            load_to_impls(a0, a1, |buf| impls.load_tx_hash(buf, a2 as usize))
467        }
468        consts::SYS_LOAD_WITNESS => load_to_impls(a0, a1, |buf| {
469            let source: Source = a4.try_into().expect("parse source");
470            impls.load_witness(buf, a2 as usize, a3 as usize, source)
471        }),
472        consts::SYS_VM_VERSION => impls.vm_version(),
473        consts::SYS_CURRENT_CYCLES => impls.current_cycles(),
474        consts::SYS_EXEC => {
475            let source: Source = a1.try_into().expect("parse source");
476            let argv = build_argv(a4, a5 as *const *const i8);
477            match impls.exec(a0 as usize, source, a2 as usize, a3 as usize, &argv) {
478                Ok(()) => 0,
479                Err(e) => e.into(),
480            }
481        }
482        consts::SYS_SPAWN => {
483            let source: Source = a1.try_into().expect("parse source");
484            let spgs_addr = a4 as *mut SpawnArgs;
485            let spgs: &mut SpawnArgs = unsafe { &mut *spgs_addr };
486
487            let argv = build_argv(spgs.argc, spgs.argv);
488            let mut fds = Vec::new();
489            let mut fd_ptr: *const u64 = spgs.inherited_fds;
490            loop {
491                let fd = unsafe { fd_ptr.read() };
492                if fd == 0 {
493                    break;
494                }
495                fds.push(fd);
496                fd_ptr = unsafe { fd_ptr.offset(1) };
497            }
498            match impls.spawn(a0 as usize, source, a2 as usize, a3 as usize, &argv, &fds) {
499                Ok(process_id) => {
500                    unsafe { spgs.process_id.write(process_id) };
501                    0
502                }
503                Err(e) => e.into(),
504            }
505        }
506        consts::SYS_PIPE => {
507            let fds = a0 as *mut u64;
508            match impls.pipe() {
509                Ok((fd1, fd2)) => {
510                    unsafe { fds.write(fd1) };
511                    unsafe { fds.offset(1).write(fd2) };
512                    0
513                }
514                Err(e) => e.into(),
515            }
516        }
517        consts::SYS_INHERITED_FDS => {
518            let fds_ptr = a0 as *mut u64;
519            let length_ptr = a1 as *mut u64;
520            let length = unsafe { length_ptr.read() } as usize;
521            let fds = unsafe { core::slice::from_raw_parts_mut(fds_ptr, length) };
522
523            match impls.inherited_fds(fds) {
524                Ok(actual_length) => {
525                    unsafe { length_ptr.write(actual_length as u64) };
526                    0
527                }
528                Err(e) => e.into(),
529            }
530        }
531        consts::SYS_READ => {
532            let buffer_ptr = a1 as *mut u8;
533            let length_ptr = a2 as *mut u64;
534            let length = unsafe { length_ptr.read() } as usize;
535            let buffer = unsafe { core::slice::from_raw_parts_mut(buffer_ptr, length) };
536
537            match impls.read(a0, buffer) {
538                Ok(read) => {
539                    unsafe { length_ptr.write(read as u64) };
540                    0
541                }
542                Err(e) => e.into(),
543            }
544        }
545        consts::SYS_WRITE => {
546            let buffer_ptr = a1 as *const u8;
547            let length_ptr = a2 as *mut u64;
548            let length = unsafe { length_ptr.read() } as usize;
549            let buffer = unsafe { core::slice::from_raw_parts(buffer_ptr, length) };
550
551            match impls.write(a0, buffer) {
552                Ok(read) => {
553                    unsafe { length_ptr.write(read as u64) };
554                    0
555                }
556                Err(e) => e.into(),
557            }
558        }
559        consts::SYS_CLOSE => match impls.close(a0) {
560            Ok(()) => 0,
561            Err(e) => e.into(),
562        },
563        consts::SYS_WAIT => match impls.wait(a0) {
564            Ok(exit_code) => {
565                let p = a1 as *mut i8;
566                unsafe { p.write(exit_code) };
567                0
568            }
569            Err(e) => e.into(),
570        },
571        consts::SYS_PROCESS_ID => impls.process_id(),
572        consts::SYS_LOAD_BLOCK_EXTENSION => load_to_impls(a0, a1, |buf| {
573            let source: Source = a4.try_into().expect("parse source");
574            impls.load_block_extension(buf, a2 as usize, a3 as usize, source)
575        }),
576        _ => panic!("Unknown syscall: {}", n),
577    }
578}
579
580fn build_argv<'a>(argc: u64, argv_ptr: *const *const i8) -> Vec<&'a CStr> {
581    let mut argv = Vec::with_capacity(argc as usize);
582    for i in 0..argc as isize {
583        let p: *const i8 = unsafe { argv_ptr.offset(i as isize).read() };
584        argv.push(unsafe { CStr::from_ptr(p as *const _) });
585    }
586    argv
587}
588
589fn load_to_impls<F>(a0: u64, a1: u64, f: F) -> u64
590where
591    F: Fn(&mut [u8]) -> IoResult,
592{
593    let buf_ptr = a0 as *mut u8;
594    let length_ptr = a1 as *mut u64;
595
596    let length = unsafe { length_ptr.read() };
597    let buf = unsafe { core::slice::from_raw_parts_mut(buf_ptr, length as usize) };
598
599    match f(buf) {
600        IoResult::FullyLoaded(loaded) => {
601            unsafe { length_ptr.write(loaded as u64) };
602            0
603        }
604        IoResult::PartialLoaded { available, .. } => {
605            unsafe { length_ptr.write(available as u64) };
606            0
607        }
608        IoResult::Error(e) => e.into(),
609    }
610}
611
612/// Error defined here differs from SysError: it only captures true CKB
613/// errors. It is not considered an error when a partial loading function
614/// reads part, but not all of the data.
615#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
616pub enum Error {
617    IndexOutOfBound,
618    ItemMissing,
619    SliceOutOfBound,
620    WrongFormat,
621    WaitFailure,
622    InvalidFd,
623    OtherEndClosed,
624    MaxVmsSpawned,
625    MaxFdsCreated,
626    Other(u64),
627}
628
629impl From<Error> for u64 {
630    fn from(e: Error) -> u64 {
631        match e {
632            Error::IndexOutOfBound => 1,
633            Error::ItemMissing => 2,
634            Error::SliceOutOfBound => 3,
635            Error::WrongFormat => 4,
636            Error::WaitFailure => 5,
637            Error::InvalidFd => 6,
638            Error::OtherEndClosed => 7,
639            Error::MaxVmsSpawned => 8,
640            Error::MaxFdsCreated => 9,
641            Error::Other(e) => e,
642        }
643    }
644}
645
646pub fn build_result(v: u64) -> Result<(), Error> {
647    if v == 0 {
648        Ok(())
649    } else {
650        Err(v.try_into().unwrap())
651    }
652}
653
654impl TryFrom<u64> for Error {
655    type Error = &'static str;
656
657    fn try_from(v: u64) -> Result<Self, Self::Error> {
658        match v {
659            0 => Err("Error cannot be zero!"),
660            1 => Ok(Error::IndexOutOfBound),
661            2 => Ok(Error::ItemMissing),
662            3 => Ok(Error::SliceOutOfBound),
663            4 => Ok(Error::WrongFormat),
664            5 => Ok(Error::WaitFailure),
665            6 => Ok(Error::InvalidFd),
666            7 => Ok(Error::OtherEndClosed),
667            8 => Ok(Error::MaxVmsSpawned),
668            9 => Ok(Error::MaxFdsCreated),
669            _ => Ok(Error::Other(v)),
670        }
671    }
672}
673
674/// IoResult captures response from partial loading function.
675#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
676pub enum IoResult {
677    FullyLoaded(usize),
678    PartialLoaded { loaded: usize, available: usize },
679    Error(Error),
680}
681
682impl IoResult {
683    pub fn to_result(&self) -> Result<(), Error> {
684        match self {
685            IoResult::FullyLoaded(_) => Ok(()),
686            IoResult::PartialLoaded { .. } => Ok(()),
687            IoResult::Error(e) => Err(*e),
688        }
689    }
690
691    pub fn loaded(&self) -> Option<usize> {
692        match self {
693            IoResult::FullyLoaded(l) => Some(*l),
694            IoResult::PartialLoaded { loaded, .. } => Some(*loaded),
695            IoResult::Error(_) => None,
696        }
697    }
698
699    pub fn available(&self) -> Option<usize> {
700        match self {
701            IoResult::FullyLoaded(l) => Some(*l),
702            IoResult::PartialLoaded { available, .. } => Some(*available),
703            IoResult::Error(_) => None,
704        }
705    }
706}
707
708impl From<Error> for IoResult {
709    fn from(e: Error) -> IoResult {
710        IoResult::Error(e)
711    }
712}
713
714impl From<IoResult> for Result<usize, SysError> {
715    fn from(result: IoResult) -> Result<usize, SysError> {
716        match result {
717            IoResult::FullyLoaded(l) => Ok(l),
718            IoResult::PartialLoaded { available, .. } => Err(SysError::LengthNotEnough(available)),
719            IoResult::Error(e) => Err(e.into()),
720        }
721    }
722}
723
724impl From<Error> for SysError {
725    fn from(e: Error) -> SysError {
726        match e {
727            Error::IndexOutOfBound => SysError::IndexOutOfBound,
728            Error::ItemMissing => SysError::ItemMissing,
729            Error::SliceOutOfBound => SysError::Encoding,
730            Error::WrongFormat => SysError::Unknown(4),
731            Error::WaitFailure => SysError::WaitFailure,
732            Error::InvalidFd => SysError::InvalidFd,
733            Error::OtherEndClosed => SysError::OtherEndClosed,
734            Error::MaxVmsSpawned => SysError::MaxVmsSpawned,
735            Error::MaxFdsCreated => SysError::MaxFdsCreated,
736            Error::Other(e) => SysError::Unknown(e),
737        }
738    }
739}