Skip to main content

proxy_wasm/
hostcalls.rs

1// Copyright 2020 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use crate::dispatcher;
16use crate::types::*;
17use std::ptr::{null, null_mut};
18use std::time::{Duration, SystemTime, UNIX_EPOCH};
19
20#[link(wasm_import_module = "env")]
21extern "C" {
22    fn proxy_log(level: LogLevel, message_data: *const u8, message_size: usize) -> Status;
23}
24
25pub fn log(level: LogLevel, message: &str) -> Result<(), Status> {
26    unsafe {
27        match proxy_log(level, message.as_ptr(), message.len()) {
28            Status::Ok => Ok(()),
29            status => panic!("unexpected status: {}", status as u32),
30        }
31    }
32}
33
34#[link(wasm_import_module = "env")]
35extern "C" {
36    fn proxy_get_log_level(return_level: *mut LogLevel) -> Status;
37}
38
39pub fn get_log_level() -> Result<LogLevel, Status> {
40    let mut return_level: LogLevel = LogLevel::Trace;
41    unsafe {
42        match proxy_get_log_level(&mut return_level) {
43            Status::Ok => Ok(return_level),
44            status => panic!("unexpected status: {}", status as u32),
45        }
46    }
47}
48
49#[link(wasm_import_module = "env")]
50extern "C" {
51    fn proxy_get_current_time_nanoseconds(return_time: *mut u64) -> Status;
52}
53
54pub fn get_current_time() -> Result<SystemTime, Status> {
55    let mut return_time: u64 = 0;
56    unsafe {
57        match proxy_get_current_time_nanoseconds(&mut return_time) {
58            Status::Ok => Ok(UNIX_EPOCH + Duration::from_nanos(return_time)),
59            status => panic!("unexpected status: {}", status as u32),
60        }
61    }
62}
63
64#[link(wasm_import_module = "env")]
65extern "C" {
66    fn proxy_set_tick_period_milliseconds(period: u32) -> Status;
67}
68
69pub fn set_tick_period(period: Duration) -> Result<(), Status> {
70    unsafe {
71        match proxy_set_tick_period_milliseconds(period.as_millis() as u32) {
72            Status::Ok => Ok(()),
73            status => panic!("unexpected status: {}", status as u32),
74        }
75    }
76}
77
78#[link(wasm_import_module = "env")]
79extern "C" {
80    fn proxy_get_buffer_bytes(
81        buffer_type: BufferType,
82        start: usize,
83        max_size: usize,
84        return_buffer_data: *mut *mut u8,
85        return_buffer_size: *mut usize,
86    ) -> Status;
87}
88
89pub fn get_buffer(
90    buffer_type: BufferType,
91    start: usize,
92    max_size: usize,
93) -> Result<Option<Bytes>, Status> {
94    let mut return_data: *mut u8 = null_mut();
95    let mut return_size: usize = 0;
96    unsafe {
97        match proxy_get_buffer_bytes(
98            buffer_type,
99            start,
100            max_size,
101            &mut return_data,
102            &mut return_size,
103        ) {
104            Status::Ok => {
105                if !return_data.is_null() {
106                    Ok(Some(Vec::from_raw_parts(
107                        return_data,
108                        return_size,
109                        return_size,
110                    )))
111                } else {
112                    Ok(None)
113                }
114            }
115            Status::NotFound => Ok(None),
116            status => panic!("unexpected status: {}", status as u32),
117        }
118    }
119}
120
121#[link(wasm_import_module = "env")]
122extern "C" {
123    fn proxy_set_buffer_bytes(
124        buffer_type: BufferType,
125        start: usize,
126        size: usize,
127        buffer_data: *const u8,
128        buffer_size: usize,
129    ) -> Status;
130}
131
132pub fn set_buffer(
133    buffer_type: BufferType,
134    start: usize,
135    size: usize,
136    value: &[u8],
137) -> Result<(), Status> {
138    unsafe {
139        match proxy_set_buffer_bytes(buffer_type, start, size, value.as_ptr(), value.len()) {
140            Status::Ok => Ok(()),
141            status => panic!("unexpected status: {}", status as u32),
142        }
143    }
144}
145
146#[cfg(not(all(test, feature = "mockalloc")))]
147#[link(wasm_import_module = "env")]
148extern "C" {
149    fn proxy_get_header_map_pairs(
150        map_type: MapType,
151        return_map_data: *mut *mut u8,
152        return_map_size: *mut usize,
153    ) -> Status;
154}
155
156#[cfg(all(test, feature = "mockalloc"))]
157fn proxy_get_header_map_pairs(
158    map_type: MapType,
159    return_map_data: *mut *mut u8,
160    return_map_size: *mut usize,
161) -> Status {
162    mocks::proxy_get_header_map_pairs(map_type, return_map_data, return_map_size)
163}
164
165pub fn get_map(map_type: MapType) -> Result<Vec<(String, String)>, Status> {
166    unsafe {
167        let mut return_data: *mut u8 = null_mut();
168        let mut return_size: usize = 0;
169        match proxy_get_header_map_pairs(map_type, &mut return_data, &mut return_size) {
170            Status::Ok => {
171                if !return_data.is_null() {
172                    let serialized_map = Vec::from_raw_parts(return_data, return_size, return_size);
173                    Ok(utils::deserialize_map(&serialized_map))
174                } else {
175                    Ok(Vec::new())
176                }
177            }
178            status => panic!("unexpected status: {}", status as u32),
179        }
180    }
181}
182
183pub fn get_map_bytes(map_type: MapType) -> Result<Vec<(String, Bytes)>, Status> {
184    unsafe {
185        let mut return_data: *mut u8 = null_mut();
186        let mut return_size: usize = 0;
187        match proxy_get_header_map_pairs(map_type, &mut return_data, &mut return_size) {
188            Status::Ok => {
189                if !return_data.is_null() {
190                    let serialized_map = Vec::from_raw_parts(return_data, return_size, return_size);
191                    Ok(utils::deserialize_map_bytes(&serialized_map))
192                } else {
193                    Ok(Vec::new())
194                }
195            }
196            status => panic!("unexpected status: {}", status as u32),
197        }
198    }
199}
200
201#[link(wasm_import_module = "env")]
202extern "C" {
203    fn proxy_set_header_map_pairs(
204        map_type: MapType,
205        map_data: *const u8,
206        map_size: usize,
207    ) -> Status;
208}
209
210pub fn set_map(map_type: MapType, map: Vec<(&str, &str)>) -> Result<(), Status> {
211    let serialized_map = utils::serialize_map(&map);
212    unsafe {
213        match proxy_set_header_map_pairs(map_type, serialized_map.as_ptr(), serialized_map.len()) {
214            Status::Ok => Ok(()),
215            status => panic!("unexpected status: {}", status as u32),
216        }
217    }
218}
219
220pub fn set_map_bytes(map_type: MapType, map: Vec<(&str, &[u8])>) -> Result<(), Status> {
221    let serialized_map = utils::serialize_map_bytes(&map);
222    unsafe {
223        match proxy_set_header_map_pairs(map_type, serialized_map.as_ptr(), serialized_map.len()) {
224            Status::Ok => Ok(()),
225            status => panic!("unexpected status: {}", status as u32),
226        }
227    }
228}
229
230#[link(wasm_import_module = "env")]
231extern "C" {
232    fn proxy_get_header_map_value(
233        map_type: MapType,
234        key_data: *const u8,
235        key_size: usize,
236        return_value_data: *mut *mut u8,
237        return_value_size: *mut usize,
238    ) -> Status;
239}
240
241pub fn get_map_value(map_type: MapType, key: &str) -> Result<Option<String>, Status> {
242    let mut return_data: *mut u8 = null_mut();
243    let mut return_size: usize = 0;
244    unsafe {
245        match proxy_get_header_map_value(
246            map_type,
247            key.as_ptr(),
248            key.len(),
249            &mut return_data,
250            &mut return_size,
251        ) {
252            Status::Ok => {
253                if !return_data.is_null() {
254                    Ok(Some(
255                        String::from_utf8(Vec::from_raw_parts(
256                            return_data,
257                            return_size,
258                            return_size,
259                        ))
260                        .unwrap(),
261                    ))
262                } else {
263                    Ok(Some(String::new()))
264                }
265            }
266            Status::NotFound => Ok(None),
267            status => panic!("unexpected status: {}", status as u32),
268        }
269    }
270}
271
272pub fn get_map_value_bytes(map_type: MapType, key: &str) -> Result<Option<Bytes>, Status> {
273    let mut return_data: *mut u8 = null_mut();
274    let mut return_size: usize = 0;
275    unsafe {
276        match proxy_get_header_map_value(
277            map_type,
278            key.as_ptr(),
279            key.len(),
280            &mut return_data,
281            &mut return_size,
282        ) {
283            Status::Ok => {
284                if !return_data.is_null() {
285                    Ok(Some(Vec::from_raw_parts(
286                        return_data,
287                        return_size,
288                        return_size,
289                    )))
290                } else {
291                    Ok(Some(Vec::new()))
292                }
293            }
294            Status::NotFound => Ok(None),
295            status => panic!("unexpected status: {}", status as u32),
296        }
297    }
298}
299
300#[link(wasm_import_module = "env")]
301extern "C" {
302    fn proxy_remove_header_map_value(
303        map_type: MapType,
304        key_data: *const u8,
305        key_size: usize,
306    ) -> Status;
307}
308
309pub fn remove_map_value(map_type: MapType, key: &str) -> Result<(), Status> {
310    unsafe {
311        match proxy_remove_header_map_value(map_type, key.as_ptr(), key.len()) {
312            Status::Ok => Ok(()),
313            status => panic!("unexpected status: {}", status as u32),
314        }
315    }
316}
317
318#[link(wasm_import_module = "env")]
319extern "C" {
320    fn proxy_replace_header_map_value(
321        map_type: MapType,
322        key_data: *const u8,
323        key_size: usize,
324        value_data: *const u8,
325        value_size: usize,
326    ) -> Status;
327}
328
329pub fn set_map_value(map_type: MapType, key: &str, value: Option<&str>) -> Result<(), Status> {
330    unsafe {
331        if let Some(value) = value {
332            match proxy_replace_header_map_value(
333                map_type,
334                key.as_ptr(),
335                key.len(),
336                value.as_ptr(),
337                value.len(),
338            ) {
339                Status::Ok => Ok(()),
340                status => panic!("unexpected status: {}", status as u32),
341            }
342        } else {
343            match proxy_remove_header_map_value(map_type, key.as_ptr(), key.len()) {
344                Status::Ok => Ok(()),
345                status => panic!("unexpected status: {}", status as u32),
346            }
347        }
348    }
349}
350
351pub fn set_map_value_bytes(
352    map_type: MapType,
353    key: &str,
354    value: Option<&[u8]>,
355) -> Result<(), Status> {
356    unsafe {
357        if let Some(value) = value {
358            match proxy_replace_header_map_value(
359                map_type,
360                key.as_ptr(),
361                key.len(),
362                value.as_ptr(),
363                value.len(),
364            ) {
365                Status::Ok => Ok(()),
366                status => panic!("unexpected status: {}", status as u32),
367            }
368        } else {
369            match proxy_remove_header_map_value(map_type, key.as_ptr(), key.len()) {
370                Status::Ok => Ok(()),
371                status => panic!("unexpected status: {}", status as u32),
372            }
373        }
374    }
375}
376
377#[link(wasm_import_module = "env")]
378extern "C" {
379    fn proxy_add_header_map_value(
380        map_type: MapType,
381        key_data: *const u8,
382        key_size: usize,
383        value_data: *const u8,
384        value_size: usize,
385    ) -> Status;
386}
387
388pub fn add_map_value(map_type: MapType, key: &str, value: &str) -> Result<(), Status> {
389    unsafe {
390        match proxy_add_header_map_value(
391            map_type,
392            key.as_ptr(),
393            key.len(),
394            value.as_ptr(),
395            value.len(),
396        ) {
397            Status::Ok => Ok(()),
398            status => panic!("unexpected status: {}", status as u32),
399        }
400    }
401}
402
403pub fn add_map_value_bytes(map_type: MapType, key: &str, value: &[u8]) -> Result<(), Status> {
404    unsafe {
405        match proxy_add_header_map_value(
406            map_type,
407            key.as_ptr(),
408            key.len(),
409            value.as_ptr(),
410            value.len(),
411        ) {
412            Status::Ok => Ok(()),
413            status => panic!("unexpected status: {}", status as u32),
414        }
415    }
416}
417
418#[link(wasm_import_module = "env")]
419extern "C" {
420    fn proxy_get_property(
421        path_data: *const u8,
422        path_size: usize,
423        return_value_data: *mut *mut u8,
424        return_value_size: *mut usize,
425    ) -> Status;
426}
427
428pub fn get_property(path: Vec<&str>) -> Result<Option<Bytes>, Status> {
429    let serialized_path = utils::serialize_property_path(path);
430    let mut return_data: *mut u8 = null_mut();
431    let mut return_size: usize = 0;
432    unsafe {
433        match proxy_get_property(
434            serialized_path.as_ptr(),
435            serialized_path.len(),
436            &mut return_data,
437            &mut return_size,
438        ) {
439            Status::Ok => {
440                if !return_data.is_null() {
441                    Ok(Some(Vec::from_raw_parts(
442                        return_data,
443                        return_size,
444                        return_size,
445                    )))
446                } else {
447                    Ok(None)
448                }
449            }
450            Status::NotFound => Ok(None),
451            Status::SerializationFailure => Err(Status::SerializationFailure),
452            Status::InternalFailure => Err(Status::InternalFailure),
453            status => panic!("unexpected status: {}", status as u32),
454        }
455    }
456}
457
458#[link(wasm_import_module = "env")]
459extern "C" {
460    fn proxy_set_property(
461        path_data: *const u8,
462        path_size: usize,
463        value_data: *const u8,
464        value_size: usize,
465    ) -> Status;
466}
467
468pub fn set_property(path: Vec<&str>, value: Option<&[u8]>) -> Result<(), Status> {
469    let serialized_path = utils::serialize_property_path(path);
470    unsafe {
471        match proxy_set_property(
472            serialized_path.as_ptr(),
473            serialized_path.len(),
474            value.map_or(null(), |value| value.as_ptr()),
475            value.map_or(0, |value| value.len()),
476        ) {
477            Status::Ok => Ok(()),
478            status => panic!("unexpected status: {}", status as u32),
479        }
480    }
481}
482
483#[link(wasm_import_module = "env")]
484extern "C" {
485    fn proxy_get_shared_data(
486        key_data: *const u8,
487        key_size: usize,
488        return_value_data: *mut *mut u8,
489        return_value_size: *mut usize,
490        return_cas: *mut u32,
491    ) -> Status;
492}
493
494pub fn get_shared_data(key: &str) -> Result<(Option<Bytes>, Option<u32>), Status> {
495    let mut return_data: *mut u8 = null_mut();
496    let mut return_size: usize = 0;
497    let mut return_cas: u32 = 0;
498    unsafe {
499        match proxy_get_shared_data(
500            key.as_ptr(),
501            key.len(),
502            &mut return_data,
503            &mut return_size,
504            &mut return_cas,
505        ) {
506            Status::Ok => {
507                let cas = match return_cas {
508                    0 => None,
509                    cas => Some(cas),
510                };
511                if !return_data.is_null() {
512                    Ok((
513                        Some(Vec::from_raw_parts(return_data, return_size, return_size)),
514                        cas,
515                    ))
516                } else {
517                    Ok((None, cas))
518                }
519            }
520            Status::NotFound => Ok((None, None)),
521            status => panic!("unexpected status: {}", status as u32),
522        }
523    }
524}
525
526#[link(wasm_import_module = "env")]
527extern "C" {
528    fn proxy_set_shared_data(
529        key_data: *const u8,
530        key_size: usize,
531        value_data: *const u8,
532        value_size: usize,
533        cas: u32,
534    ) -> Status;
535}
536
537pub fn set_shared_data(key: &str, value: Option<&[u8]>, cas: Option<u32>) -> Result<(), Status> {
538    unsafe {
539        match proxy_set_shared_data(
540            key.as_ptr(),
541            key.len(),
542            value.map_or(null(), |value| value.as_ptr()),
543            value.map_or(0, |value| value.len()),
544            cas.unwrap_or(0),
545        ) {
546            Status::Ok => Ok(()),
547            Status::CasMismatch => Err(Status::CasMismatch),
548            status => panic!("unexpected status: {}", status as u32),
549        }
550    }
551}
552
553#[link(wasm_import_module = "env")]
554extern "C" {
555    fn proxy_register_shared_queue(
556        name_data: *const u8,
557        name_size: usize,
558        return_id: *mut u32,
559    ) -> Status;
560}
561
562pub fn register_shared_queue(name: &str) -> Result<u32, Status> {
563    unsafe {
564        let mut return_id: u32 = 0;
565        match proxy_register_shared_queue(name.as_ptr(), name.len(), &mut return_id) {
566            Status::Ok => Ok(return_id),
567            status => panic!("unexpected status: {}", status as u32),
568        }
569    }
570}
571
572#[link(wasm_import_module = "env")]
573extern "C" {
574    fn proxy_resolve_shared_queue(
575        vm_id_data: *const u8,
576        vm_id_size: usize,
577        name_data: *const u8,
578        name_size: usize,
579        return_id: *mut u32,
580    ) -> Status;
581}
582
583pub fn resolve_shared_queue(vm_id: &str, name: &str) -> Result<Option<u32>, Status> {
584    let mut return_id: u32 = 0;
585    unsafe {
586        match proxy_resolve_shared_queue(
587            vm_id.as_ptr(),
588            vm_id.len(),
589            name.as_ptr(),
590            name.len(),
591            &mut return_id,
592        ) {
593            Status::Ok => Ok(Some(return_id)),
594            Status::NotFound => Ok(None),
595            status => panic!("unexpected status: {}", status as u32),
596        }
597    }
598}
599
600#[link(wasm_import_module = "env")]
601extern "C" {
602    fn proxy_dequeue_shared_queue(
603        queue_id: u32,
604        return_value_data: *mut *mut u8,
605        return_value_size: *mut usize,
606    ) -> Status;
607}
608
609pub fn dequeue_shared_queue(queue_id: u32) -> Result<Option<Bytes>, Status> {
610    let mut return_data: *mut u8 = null_mut();
611    let mut return_size: usize = 0;
612    unsafe {
613        match proxy_dequeue_shared_queue(queue_id, &mut return_data, &mut return_size) {
614            Status::Ok => {
615                if !return_data.is_null() {
616                    Ok(Some(Vec::from_raw_parts(
617                        return_data,
618                        return_size,
619                        return_size,
620                    )))
621                } else {
622                    Ok(None)
623                }
624            }
625            Status::Empty => Ok(None),
626            Status::NotFound => Err(Status::NotFound),
627            status => panic!("unexpected status: {}", status as u32),
628        }
629    }
630}
631
632#[link(wasm_import_module = "env")]
633extern "C" {
634    fn proxy_enqueue_shared_queue(
635        queue_id: u32,
636        value_data: *const u8,
637        value_size: usize,
638    ) -> Status;
639}
640
641pub fn enqueue_shared_queue(queue_id: u32, value: Option<&[u8]>) -> Result<(), Status> {
642    unsafe {
643        match proxy_enqueue_shared_queue(
644            queue_id,
645            value.map_or(null(), |value| value.as_ptr()),
646            value.map_or(0, |value| value.len()),
647        ) {
648            Status::Ok => Ok(()),
649            Status::NotFound => Err(Status::NotFound),
650            status => panic!("unexpected status: {}", status as u32),
651        }
652    }
653}
654
655#[link(wasm_import_module = "env")]
656extern "C" {
657    fn proxy_continue_stream(stream_type: StreamType) -> Status;
658}
659
660pub fn resume_downstream() -> Result<(), Status> {
661    unsafe {
662        match proxy_continue_stream(StreamType::Downstream) {
663            Status::Ok => Ok(()),
664            status => panic!("unexpected status: {}", status as u32),
665        }
666    }
667}
668
669pub fn resume_upstream() -> Result<(), Status> {
670    unsafe {
671        match proxy_continue_stream(StreamType::Upstream) {
672            Status::Ok => Ok(()),
673            status => panic!("unexpected status: {}", status as u32),
674        }
675    }
676}
677
678pub fn resume_http_request() -> Result<(), Status> {
679    unsafe {
680        match proxy_continue_stream(StreamType::HttpRequest) {
681            Status::Ok => Ok(()),
682            status => panic!("unexpected status: {}", status as u32),
683        }
684    }
685}
686
687pub fn resume_http_response() -> Result<(), Status> {
688    unsafe {
689        match proxy_continue_stream(StreamType::HttpResponse) {
690            Status::Ok => Ok(()),
691            status => panic!("unexpected status: {}", status as u32),
692        }
693    }
694}
695
696#[link(wasm_import_module = "env")]
697extern "C" {
698    fn proxy_close_stream(stream_type: StreamType) -> Status;
699}
700
701pub fn close_downstream() -> Result<(), Status> {
702    unsafe {
703        match proxy_close_stream(StreamType::Downstream) {
704            Status::Ok => Ok(()),
705            status => panic!("unexpected status: {}", status as u32),
706        }
707    }
708}
709pub fn close_upstream() -> Result<(), Status> {
710    unsafe {
711        match proxy_close_stream(StreamType::Upstream) {
712            Status::Ok => Ok(()),
713            status => panic!("unexpected status: {}", status as u32),
714        }
715    }
716}
717
718pub fn reset_http_request() -> Result<(), Status> {
719    unsafe {
720        match proxy_close_stream(StreamType::HttpRequest) {
721            Status::Ok => Ok(()),
722            status => panic!("unexpected status: {}", status as u32),
723        }
724    }
725}
726
727pub fn reset_http_response() -> Result<(), Status> {
728    unsafe {
729        match proxy_close_stream(StreamType::HttpResponse) {
730            Status::Ok => Ok(()),
731            status => panic!("unexpected status: {}", status as u32),
732        }
733    }
734}
735
736#[link(wasm_import_module = "env")]
737extern "C" {
738    fn proxy_send_local_response(
739        status_code: u32,
740        status_code_details_data: *const u8,
741        status_code_details_size: usize,
742        body_data: *const u8,
743        body_size: usize,
744        headers_data: *const u8,
745        headers_size: usize,
746        grpc_status: i32,
747    ) -> Status;
748}
749
750pub fn send_http_response(
751    status_code: u32,
752    headers: Vec<(&str, &str)>,
753    body: Option<&[u8]>,
754) -> Result<(), Status> {
755    let serialized_headers = utils::serialize_map(&headers);
756    unsafe {
757        match proxy_send_local_response(
758            status_code,
759            null(),
760            0,
761            body.map_or(null(), |body| body.as_ptr()),
762            body.map_or(0, |body| body.len()),
763            serialized_headers.as_ptr(),
764            serialized_headers.len(),
765            -1,
766        ) {
767            Status::Ok => Ok(()),
768            status => panic!("unexpected status: {}", status as u32),
769        }
770    }
771}
772
773pub fn send_grpc_response(
774    grpc_status: GrpcStatusCode,
775    grpc_status_message: Option<&str>,
776    custom_metadata: Vec<(&str, &[u8])>,
777) -> Result<(), Status> {
778    let serialized_custom_metadata = utils::serialize_map_bytes(&custom_metadata);
779    unsafe {
780        match proxy_send_local_response(
781            200,
782            null(),
783            0,
784            grpc_status_message.map_or(null(), |grpc_status_message| grpc_status_message.as_ptr()),
785            grpc_status_message.map_or(0, |grpc_status_message| grpc_status_message.len()),
786            serialized_custom_metadata.as_ptr(),
787            serialized_custom_metadata.len(),
788            grpc_status as i32,
789        ) {
790            Status::Ok => Ok(()),
791            status => panic!("unexpected status: {}", status as u32),
792        }
793    }
794}
795
796#[link(wasm_import_module = "env")]
797extern "C" {
798    fn proxy_http_call(
799        upstream_data: *const u8,
800        upstream_size: usize,
801        headers_data: *const u8,
802        headers_size: usize,
803        body_data: *const u8,
804        body_size: usize,
805        trailers_data: *const u8,
806        trailers_size: usize,
807        timeout: u32,
808        return_token: *mut u32,
809    ) -> Status;
810}
811
812pub fn dispatch_http_call(
813    upstream: &str,
814    headers: Vec<(&str, &str)>,
815    body: Option<&[u8]>,
816    trailers: Vec<(&str, &str)>,
817    timeout: Duration,
818) -> Result<u32, Status> {
819    let serialized_headers = utils::serialize_map(&headers);
820    let serialized_trailers = utils::serialize_map(&trailers);
821    let mut return_token: u32 = 0;
822    unsafe {
823        match proxy_http_call(
824            upstream.as_ptr(),
825            upstream.len(),
826            serialized_headers.as_ptr(),
827            serialized_headers.len(),
828            body.map_or(null(), |body| body.as_ptr()),
829            body.map_or(0, |body| body.len()),
830            serialized_trailers.as_ptr(),
831            serialized_trailers.len(),
832            timeout.as_millis() as u32,
833            &mut return_token,
834        ) {
835            Status::Ok => {
836                dispatcher::register_callout(return_token);
837                Ok(return_token)
838            }
839            Status::BadArgument => Err(Status::BadArgument),
840            Status::InternalFailure => Err(Status::InternalFailure),
841            status => panic!("unexpected status: {}", status as u32),
842        }
843    }
844}
845
846#[link(wasm_import_module = "env")]
847extern "C" {
848    fn proxy_grpc_call(
849        upstream_data: *const u8,
850        upstream_size: usize,
851        service_name_data: *const u8,
852        service_name_size: usize,
853        method_name_data: *const u8,
854        method_name_size: usize,
855        initial_metadata_data: *const u8,
856        initial_metadata_size: usize,
857        message_data_data: *const u8,
858        message_data_size: usize,
859        timeout: u32,
860        return_callout_id: *mut u32,
861    ) -> Status;
862}
863
864pub fn dispatch_grpc_call(
865    upstream_name: &str,
866    service_name: &str,
867    method_name: &str,
868    initial_metadata: Vec<(&str, &[u8])>,
869    message: Option<&[u8]>,
870    timeout: Duration,
871) -> Result<u32, Status> {
872    let mut return_callout_id = 0;
873    let serialized_initial_metadata = utils::serialize_map_bytes(&initial_metadata);
874    unsafe {
875        match proxy_grpc_call(
876            upstream_name.as_ptr(),
877            upstream_name.len(),
878            service_name.as_ptr(),
879            service_name.len(),
880            method_name.as_ptr(),
881            method_name.len(),
882            serialized_initial_metadata.as_ptr(),
883            serialized_initial_metadata.len(),
884            message.map_or(null(), |message| message.as_ptr()),
885            message.map_or(0, |message| message.len()),
886            timeout.as_millis() as u32,
887            &mut return_callout_id,
888        ) {
889            Status::Ok => {
890                dispatcher::register_grpc_callout(return_callout_id);
891                Ok(return_callout_id)
892            }
893            Status::ParseFailure => Err(Status::ParseFailure),
894            Status::InternalFailure => Err(Status::InternalFailure),
895            status => panic!("unexpected status: {}", status as u32),
896        }
897    }
898}
899
900#[link(wasm_import_module = "env")]
901extern "C" {
902    fn proxy_grpc_stream(
903        upstream_data: *const u8,
904        upstream_size: usize,
905        service_name_data: *const u8,
906        service_name_size: usize,
907        method_name_data: *const u8,
908        method_name_size: usize,
909        initial_metadata_data: *const u8,
910        initial_metadata_size: usize,
911        return_stream_id: *mut u32,
912    ) -> Status;
913}
914
915pub fn open_grpc_stream(
916    upstream_name: &str,
917    service_name: &str,
918    method_name: &str,
919    initial_metadata: Vec<(&str, &[u8])>,
920) -> Result<u32, Status> {
921    let mut return_stream_id = 0;
922    let serialized_initial_metadata = utils::serialize_map_bytes(&initial_metadata);
923    unsafe {
924        match proxy_grpc_stream(
925            upstream_name.as_ptr(),
926            upstream_name.len(),
927            service_name.as_ptr(),
928            service_name.len(),
929            method_name.as_ptr(),
930            method_name.len(),
931            serialized_initial_metadata.as_ptr(),
932            serialized_initial_metadata.len(),
933            &mut return_stream_id,
934        ) {
935            Status::Ok => {
936                dispatcher::register_grpc_stream(return_stream_id);
937                Ok(return_stream_id)
938            }
939            Status::ParseFailure => Err(Status::ParseFailure),
940            Status::InternalFailure => Err(Status::InternalFailure),
941            status => panic!("unexpected status: {}", status as u32),
942        }
943    }
944}
945
946#[link(wasm_import_module = "env")]
947extern "C" {
948    fn proxy_grpc_send(
949        token: u32,
950        message_ptr: *const u8,
951        message_len: usize,
952        end_stream: bool,
953    ) -> Status;
954}
955
956pub fn send_grpc_stream_message(
957    token: u32,
958    message: Option<&[u8]>,
959    end_stream: bool,
960) -> Result<(), Status> {
961    unsafe {
962        match proxy_grpc_send(
963            token,
964            message.map_or(null(), |message| message.as_ptr()),
965            message.map_or(0, |message| message.len()),
966            end_stream,
967        ) {
968            Status::Ok => Ok(()),
969            Status::BadArgument => Err(Status::BadArgument),
970            Status::NotFound => Err(Status::NotFound),
971            status => panic!("unexpected status: {}", status as u32),
972        }
973    }
974}
975
976#[link(wasm_import_module = "env")]
977extern "C" {
978    fn proxy_grpc_cancel(token_id: u32) -> Status;
979}
980
981pub fn cancel_grpc_call(token_id: u32) -> Result<(), Status> {
982    unsafe {
983        match proxy_grpc_cancel(token_id) {
984            Status::Ok => Ok(()),
985            Status::NotFound => Err(Status::NotFound),
986            status => panic!("unexpected status: {}", status as u32),
987        }
988    }
989}
990
991pub fn cancel_grpc_stream(token_id: u32) -> Result<(), Status> {
992    unsafe {
993        match proxy_grpc_cancel(token_id) {
994            Status::Ok => Ok(()),
995            Status::NotFound => Err(Status::NotFound),
996            status => panic!("unexpected status: {}", status as u32),
997        }
998    }
999}
1000
1001#[link(wasm_import_module = "env")]
1002extern "C" {
1003    fn proxy_grpc_close(token_id: u32) -> Status;
1004}
1005
1006pub fn close_grpc_stream(token_id: u32) -> Result<(), Status> {
1007    unsafe {
1008        match proxy_grpc_close(token_id) {
1009            Status::Ok => Ok(()),
1010            Status::NotFound => Err(Status::NotFound),
1011            status => panic!("unexpected status: {}", status as u32),
1012        }
1013    }
1014}
1015
1016#[link(wasm_import_module = "env")]
1017extern "C" {
1018    fn proxy_get_status(
1019        return_code: *mut u32,
1020        return_message_data: *mut *mut u8,
1021        return_message_size: *mut usize,
1022    ) -> Status;
1023}
1024
1025pub fn get_grpc_status() -> Result<(u32, Option<String>), Status> {
1026    let mut return_code: u32 = 0;
1027    let mut return_data: *mut u8 = null_mut();
1028    let mut return_size: usize = 0;
1029    unsafe {
1030        match proxy_get_status(&mut return_code, &mut return_data, &mut return_size) {
1031            Status::Ok => {
1032                if !return_data.is_null() {
1033                    Ok((
1034                        return_code,
1035                        Some(
1036                            String::from_utf8(Vec::from_raw_parts(
1037                                return_data,
1038                                return_size,
1039                                return_size,
1040                            ))
1041                            .unwrap(),
1042                        ),
1043                    ))
1044                } else {
1045                    Ok((return_code, None))
1046                }
1047            }
1048            status => panic!("unexpected status: {}", status as u32),
1049        }
1050    }
1051}
1052
1053#[link(wasm_import_module = "env")]
1054extern "C" {
1055    fn proxy_set_effective_context(context_id: u32) -> Status;
1056}
1057
1058pub fn set_effective_context(context_id: u32) -> Result<(), Status> {
1059    unsafe {
1060        match proxy_set_effective_context(context_id) {
1061            Status::Ok => Ok(()),
1062            Status::BadArgument => Err(Status::BadArgument),
1063            status => panic!("unexpected status: {}", status as u32),
1064        }
1065    }
1066}
1067
1068#[link(wasm_import_module = "env")]
1069extern "C" {
1070    fn proxy_call_foreign_function(
1071        function_name_data: *const u8,
1072        function_name_size: usize,
1073        arguments_data: *const u8,
1074        arguments_size: usize,
1075        results_data: *mut *mut u8,
1076        results_size: *mut usize,
1077    ) -> Status;
1078}
1079
1080pub fn call_foreign_function(
1081    function_name: &str,
1082    arguments: Option<&[u8]>,
1083) -> Result<Option<Bytes>, Status> {
1084    let mut return_data: *mut u8 = null_mut();
1085    let mut return_size: usize = 0;
1086    unsafe {
1087        match proxy_call_foreign_function(
1088            function_name.as_ptr(),
1089            function_name.len(),
1090            arguments.map_or(null(), |arguments| arguments.as_ptr()),
1091            arguments.map_or(0, |arguments| arguments.len()),
1092            &mut return_data,
1093            &mut return_size,
1094        ) {
1095            Status::Ok => {
1096                if !return_data.is_null() {
1097                    Ok(Some(Vec::from_raw_parts(
1098                        return_data,
1099                        return_size,
1100                        return_size,
1101                    )))
1102                } else {
1103                    Ok(None)
1104                }
1105            }
1106            Status::NotFound => Err(Status::NotFound),
1107            Status::BadArgument => Err(Status::BadArgument),
1108            Status::SerializationFailure => Err(Status::SerializationFailure),
1109            Status::InternalFailure => Err(Status::InternalFailure),
1110            status => panic!("unexpected status: {}", status as u32),
1111        }
1112    }
1113}
1114
1115#[link(wasm_import_module = "env")]
1116extern "C" {
1117    fn proxy_done() -> Status;
1118}
1119
1120pub fn done() -> Result<(), Status> {
1121    unsafe {
1122        match proxy_done() {
1123            Status::Ok => Ok(()),
1124            status => panic!("unexpected status: {}", status as u32),
1125        }
1126    }
1127}
1128
1129#[link(wasm_import_module = "env")]
1130extern "C" {
1131    fn proxy_define_metric(
1132        metric_type: MetricType,
1133        name_data: *const u8,
1134        name_size: usize,
1135        return_id: *mut u32,
1136    ) -> Status;
1137}
1138
1139pub fn define_metric(metric_type: MetricType, name: &str) -> Result<u32, Status> {
1140    let mut return_id: u32 = 0;
1141    unsafe {
1142        match proxy_define_metric(metric_type, name.as_ptr(), name.len(), &mut return_id) {
1143            Status::Ok => Ok(return_id),
1144            status => panic!("unexpected status: {}", status as u32),
1145        }
1146    }
1147}
1148
1149#[link(wasm_import_module = "env")]
1150extern "C" {
1151    fn proxy_get_metric(metric_id: u32, return_value: *mut u64) -> Status;
1152}
1153
1154pub fn get_metric(metric_id: u32) -> Result<u64, Status> {
1155    let mut return_value: u64 = 0;
1156    unsafe {
1157        match proxy_get_metric(metric_id, &mut return_value) {
1158            Status::Ok => Ok(return_value),
1159            Status::NotFound => Err(Status::NotFound),
1160            Status::BadArgument => Err(Status::BadArgument),
1161            status => panic!("unexpected status: {}", status as u32),
1162        }
1163    }
1164}
1165
1166#[link(wasm_import_module = "env")]
1167extern "C" {
1168    fn proxy_record_metric(metric_id: u32, value: u64) -> Status;
1169}
1170
1171pub fn record_metric(metric_id: u32, value: u64) -> Result<(), Status> {
1172    unsafe {
1173        match proxy_record_metric(metric_id, value) {
1174            Status::Ok => Ok(()),
1175            Status::NotFound => Err(Status::NotFound),
1176            status => panic!("unexpected status: {}", status as u32),
1177        }
1178    }
1179}
1180
1181#[link(wasm_import_module = "env")]
1182extern "C" {
1183    fn proxy_increment_metric(metric_id: u32, offset: i64) -> Status;
1184}
1185
1186pub fn increment_metric(metric_id: u32, offset: i64) -> Result<(), Status> {
1187    unsafe {
1188        match proxy_increment_metric(metric_id, offset) {
1189            Status::Ok => Ok(()),
1190            Status::NotFound => Err(Status::NotFound),
1191            Status::BadArgument => Err(Status::BadArgument),
1192            status => panic!("unexpected status: {}", status as u32),
1193        }
1194    }
1195}
1196
1197#[cfg(all(test, feature = "mockalloc"))]
1198mod mocks {
1199    use crate::hostcalls::utils::tests::SERIALIZED_MAP;
1200    use crate::types::*;
1201    use std::alloc::{alloc, Layout};
1202
1203    pub fn proxy_get_header_map_pairs(
1204        _map_type: MapType,
1205        return_map_data: *mut *mut u8,
1206        return_map_size: *mut usize,
1207    ) -> Status {
1208        let layout = Layout::array::<u8>(SERIALIZED_MAP.len()).unwrap();
1209        unsafe {
1210            *return_map_data = alloc(layout);
1211            *return_map_size = SERIALIZED_MAP.len();
1212            std::ptr::copy(
1213                SERIALIZED_MAP.as_ptr(),
1214                *return_map_data,
1215                SERIALIZED_MAP.len(),
1216            );
1217        }
1218        Status::Ok
1219    }
1220}
1221
1222#[cfg(all(test, feature = "mockalloc"))]
1223mod tests {
1224    use crate::types::*;
1225    use mockalloc::Mockalloc;
1226    use std::alloc::System;
1227
1228    #[global_allocator]
1229    static ALLOCATOR: Mockalloc<System> = Mockalloc(System);
1230
1231    #[mockalloc::test]
1232    fn test_get_map_no_leaks() {
1233        let result = super::get_map(MapType::HttpRequestHeaders);
1234        assert!(result.is_ok());
1235    }
1236
1237    #[mockalloc::test]
1238    fn test_get_map_bytes_no_leaks() {
1239        let result = super::get_map_bytes(MapType::HttpRequestHeaders);
1240        assert!(result.is_ok());
1241    }
1242}
1243
1244mod utils {
1245    use crate::types::Bytes;
1246    use std::convert::TryFrom;
1247
1248    pub(super) fn serialize_property_path(path: Vec<&str>) -> Bytes {
1249        if path.is_empty() {
1250            return Vec::new();
1251        }
1252        let mut size: usize = 0;
1253        for part in &path {
1254            size += part.len() + 1;
1255        }
1256        let mut bytes: Bytes = Vec::with_capacity(size);
1257        for part in &path {
1258            bytes.extend_from_slice(part.as_bytes());
1259            bytes.push(0);
1260        }
1261        bytes.pop();
1262        bytes
1263    }
1264
1265    pub(super) fn serialize_map(map: &[(&str, &str)]) -> Bytes {
1266        let mut size: usize = 4;
1267        for (name, value) in map {
1268            size += name.len() + value.len() + 10;
1269        }
1270        let mut bytes: Bytes = Vec::with_capacity(size);
1271        bytes.extend_from_slice(&(map.len() as u32).to_le_bytes());
1272        for (name, value) in map {
1273            bytes.extend_from_slice(&(name.len() as u32).to_le_bytes());
1274            bytes.extend_from_slice(&(value.len() as u32).to_le_bytes());
1275        }
1276        for (name, value) in map {
1277            bytes.extend_from_slice(name.as_bytes());
1278            bytes.push(0);
1279            bytes.extend_from_slice(value.as_bytes());
1280            bytes.push(0);
1281        }
1282        bytes
1283    }
1284
1285    pub(super) fn serialize_map_bytes(map: &[(&str, &[u8])]) -> Bytes {
1286        let mut size: usize = 4;
1287        for (name, value) in map {
1288            size += name.len() + value.len() + 10;
1289        }
1290        let mut bytes: Bytes = Vec::with_capacity(size);
1291        bytes.extend_from_slice(&(map.len() as u32).to_le_bytes());
1292        for (name, value) in map {
1293            bytes.extend_from_slice(&(name.len() as u32).to_le_bytes());
1294            bytes.extend_from_slice(&(value.len() as u32).to_le_bytes());
1295        }
1296        for (name, value) in map {
1297            bytes.extend_from_slice(name.as_bytes());
1298            bytes.push(0);
1299            bytes.extend_from_slice(value);
1300            bytes.push(0);
1301        }
1302        bytes
1303    }
1304
1305    pub(super) fn deserialize_map(bytes: &[u8]) -> Vec<(String, String)> {
1306        if bytes.is_empty() {
1307            return Vec::new();
1308        }
1309        let size = u32::from_le_bytes(<[u8; 4]>::try_from(&bytes[0..4]).unwrap()) as usize;
1310        let mut map = Vec::with_capacity(size);
1311        let mut p = 4 + size * 8;
1312        for n in 0..size {
1313            let s = 4 + n * 8;
1314            let size = u32::from_le_bytes(<[u8; 4]>::try_from(&bytes[s..s + 4]).unwrap()) as usize;
1315            let key = bytes[p..p + size].to_vec();
1316            p += size + 1;
1317            let size =
1318                u32::from_le_bytes(<[u8; 4]>::try_from(&bytes[s + 4..s + 8]).unwrap()) as usize;
1319            let value = bytes[p..p + size].to_vec();
1320            p += size + 1;
1321            map.push((
1322                String::from_utf8(key).unwrap(),
1323                String::from_utf8(value).unwrap(),
1324            ));
1325        }
1326        map
1327    }
1328
1329    pub(super) fn deserialize_map_bytes(bytes: &[u8]) -> Vec<(String, Bytes)> {
1330        if bytes.is_empty() {
1331            return Vec::new();
1332        }
1333        let size = u32::from_le_bytes(<[u8; 4]>::try_from(&bytes[0..4]).unwrap()) as usize;
1334        let mut map = Vec::with_capacity(size);
1335        let mut p = 4 + size * 8;
1336        for n in 0..size {
1337            let s = 4 + n * 8;
1338            let size = u32::from_le_bytes(<[u8; 4]>::try_from(&bytes[s..s + 4]).unwrap()) as usize;
1339            let key = bytes[p..p + size].to_vec();
1340            p += size + 1;
1341            let size =
1342                u32::from_le_bytes(<[u8; 4]>::try_from(&bytes[s + 4..s + 8]).unwrap()) as usize;
1343            let value = bytes[p..p + size].to_vec();
1344            p += size + 1;
1345            map.push((String::from_utf8(key).unwrap(), value));
1346        }
1347        map
1348    }
1349
1350    #[cfg(test)]
1351    pub(super) mod tests {
1352        use super::*;
1353
1354        #[cfg(nightly)]
1355        use test::Bencher;
1356
1357        static MAP: &[(&str, &str)] = &[
1358            (":method", "GET"),
1359            (":path", "/bytes/1"),
1360            (":authority", "httpbin.org"),
1361            ("Powered-By", "proxy-wasm"),
1362        ];
1363
1364        #[rustfmt::skip]
1365        pub(in crate::hostcalls) static SERIALIZED_MAP: &[u8] = &[
1366            // num entries
1367            4, 0, 0, 0,
1368            // len (":method", "GET")
1369            7, 0, 0, 0, 3, 0, 0, 0,
1370            // len (":path", "/bytes/1")
1371            5, 0, 0, 0, 8, 0, 0, 0,
1372            // len (":authority", "httpbin.org")
1373            10, 0, 0, 0, 11, 0, 0, 0,
1374            // len ("Powered-By", "proxy-wasm")
1375            10, 0, 0, 0, 10, 0, 0, 0,
1376            // ":method"
1377            58, 109, 101, 116, 104, 111, 100, 0,
1378            // "GET"
1379            71, 69, 84, 0,
1380            // ":path"
1381            58, 112, 97, 116, 104, 0,
1382            // "/bytes/1"
1383            47, 98, 121, 116, 101, 115, 47, 49, 0,
1384            // ":authority"
1385            58, 97, 117, 116, 104, 111, 114, 105, 116, 121, 0,
1386            // "httpbin.org"
1387            104, 116, 116, 112, 98, 105, 110, 46, 111, 114, 103, 0,
1388            // "Powered-By"
1389            80, 111, 119, 101, 114, 101, 100, 45, 66, 121, 0,
1390            // "proxy-wasm"
1391            112, 114, 111, 120, 121, 45, 119, 97, 115, 109, 0,
1392        ];
1393
1394        #[test]
1395        fn test_serialize_map_empty() {
1396            let serialized_map = serialize_map(&[]);
1397            assert_eq!(serialized_map, [0, 0, 0, 0]);
1398        }
1399
1400        #[test]
1401        fn test_serialize_map_empty_bytes() {
1402            let serialized_map = serialize_map_bytes(&[]);
1403            assert_eq!(serialized_map, [0, 0, 0, 0]);
1404        }
1405
1406        #[test]
1407        fn test_deserialize_map_empty() {
1408            let map = deserialize_map(&[]);
1409            assert_eq!(map, []);
1410            let map = deserialize_map(&[0, 0, 0, 0]);
1411            assert_eq!(map, []);
1412        }
1413
1414        #[test]
1415        fn test_deserialize_map_empty_bytes() {
1416            let map = deserialize_map_bytes(&[]);
1417            assert_eq!(map, []);
1418            let map = deserialize_map_bytes(&[0, 0, 0, 0]);
1419            assert_eq!(map, []);
1420        }
1421
1422        #[test]
1423        fn test_serialize_map() {
1424            let serialized_map = serialize_map(MAP);
1425            assert_eq!(serialized_map, SERIALIZED_MAP);
1426        }
1427
1428        #[test]
1429        fn test_serialize_map_bytes() {
1430            let map: Vec<(&str, &[u8])> = MAP.iter().map(|x| (x.0, x.1.as_bytes())).collect();
1431            let serialized_map = serialize_map_bytes(&map);
1432            assert_eq!(serialized_map, SERIALIZED_MAP);
1433        }
1434
1435        #[test]
1436        fn test_deserialize_map() {
1437            let map = deserialize_map(SERIALIZED_MAP);
1438            assert_eq!(map.len(), MAP.len());
1439            for (got, expected) in map.into_iter().zip(MAP) {
1440                assert_eq!(got.0, expected.0);
1441                assert_eq!(got.1, expected.1);
1442            }
1443        }
1444
1445        #[test]
1446        fn test_deserialize_map_bytes() {
1447            let map = deserialize_map_bytes(SERIALIZED_MAP);
1448            assert_eq!(map.len(), MAP.len());
1449            for (got, expected) in map.into_iter().zip(MAP) {
1450                assert_eq!(got.0, expected.0);
1451                assert_eq!(got.1, expected.1.as_bytes());
1452            }
1453        }
1454
1455        #[test]
1456        fn test_deserialize_map_roundtrip() {
1457            let map = deserialize_map(SERIALIZED_MAP);
1458            // TODO(v0.3): fix arguments, so that maps can be reused without conversion.
1459            let map_refs: Vec<(&str, &str)> =
1460                map.iter().map(|x| (x.0.as_ref(), x.1.as_ref())).collect();
1461            let serialized_map = serialize_map(&map_refs);
1462            assert_eq!(serialized_map, SERIALIZED_MAP);
1463        }
1464
1465        #[test]
1466        fn test_deserialize_map_roundtrip_bytes() {
1467            let map = deserialize_map_bytes(SERIALIZED_MAP);
1468            // TODO(v0.3): fix arguments, so that maps can be reused without conversion.
1469            let map_refs: Vec<(&str, &[u8])> =
1470                map.iter().map(|x| (x.0.as_ref(), x.1.as_ref())).collect();
1471            let serialized_map = serialize_map_bytes(&map_refs);
1472            assert_eq!(serialized_map, SERIALIZED_MAP);
1473        }
1474
1475        #[test]
1476        fn test_deserialize_map_all_chars() {
1477            // 0x00-0x7f are valid single-byte UTF-8 characters.
1478            for i in 0..0x7f {
1479                let serialized_src = [1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 99, 0, i, 0];
1480                let map = deserialize_map(&serialized_src);
1481                // TODO(v0.3): fix arguments, so that maps can be reused without conversion.
1482                let map_refs: Vec<(&str, &str)> =
1483                    map.iter().map(|x| (x.0.as_ref(), x.1.as_ref())).collect();
1484                let serialized_map = serialize_map(&map_refs);
1485                assert_eq!(serialized_map, serialized_src);
1486            }
1487            // 0x80-0xff are invalid single-byte UTF-8 characters.
1488            for i in 0x80..0xff {
1489                let serialized_src = [1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 99, 0, i, 0];
1490                std::panic::set_hook(Box::new(|_| {}));
1491                let result = std::panic::catch_unwind(|| {
1492                    deserialize_map(&serialized_src);
1493                });
1494                assert!(result.is_err());
1495            }
1496        }
1497
1498        #[test]
1499        fn test_deserialize_map_all_chars_bytes() {
1500            // All 256 single-byte characters are allowed when emitting bytes.
1501            for i in 0..0xff {
1502                let serialized_src = [1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 99, 0, i, 0];
1503                let map = deserialize_map_bytes(&serialized_src);
1504                // TODO(v0.3): fix arguments, so that maps can be reused without conversion.
1505                let map_refs: Vec<(&str, &[u8])> =
1506                    map.iter().map(|x| (x.0.as_ref(), x.1.as_ref())).collect();
1507                let serialized_map = serialize_map_bytes(&map_refs);
1508                assert_eq!(serialized_map, serialized_src);
1509            }
1510        }
1511
1512        #[cfg(nightly)]
1513        #[bench]
1514        fn bench_serialize_map(b: &mut Bencher) {
1515            let map = MAP.to_vec();
1516            b.iter(|| {
1517                serialize_map(test::black_box(&map));
1518            });
1519        }
1520
1521        #[cfg(nightly)]
1522        #[bench]
1523        fn bench_serialize_map_bytes(b: &mut Bencher) {
1524            let map: Vec<(&str, &[u8])> = MAP.iter().map(|x| (x.0, x.1.as_bytes())).collect();
1525            b.iter(|| {
1526                serialize_map_bytes(test::black_box(&map));
1527            });
1528        }
1529
1530        #[cfg(nightly)]
1531        #[bench]
1532        fn bench_deserialize_map(b: &mut Bencher) {
1533            let serialized_map = SERIALIZED_MAP.to_vec();
1534            b.iter(|| {
1535                deserialize_map(test::black_box(&serialized_map));
1536            });
1537        }
1538
1539        #[cfg(nightly)]
1540        #[bench]
1541        fn bench_deserialize_map_bytes(b: &mut Bencher) {
1542            let serialized_map = SERIALIZED_MAP.to_vec();
1543            b.iter(|| {
1544                deserialize_map_bytes(test::black_box(&serialized_map));
1545            });
1546        }
1547    }
1548}