scratchstack-wrapper-aws-c-io 0.1.0-alpha.7

Scratchstack Rust wrapper around the aws-c-io library
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
use {
    bindgen::builder,
    std::{
        env::var,
        fs::{copy, create_dir_all, read_dir},
        path::{Path, PathBuf},
    },
};

const LINK_LIBS: &str = "
aws-c-io
aws-c-cal
aws-c-common
s2n
crypto
ssl
";
const INCLUDE_PATH: &str = "aws/io";
const DEP_LIBRARIES: &str = r#"aws-c-common
aws-c-cal
aws-lc"#;
const FUNCTIONS: &str = r#"
aws_io_library_init
aws_io_library_clean_up
aws_io_fatal_assert_library_initialized
aws_client_bootstrap_new
aws_client_bootstrap_new
aws_client_bootstrap_release
aws_client_bootstrap_set_alpn_callback
aws_client_bootstrap_new_socket_channel
aws_server_bootstrap_new
aws_server_bootstrap_acquire
aws_server_bootstrap_release
aws_server_bootstrap_set_alpn_callback
aws_server_bootstrap_new_socket_listener
aws_server_bootstrap_destroy_socket_listener
aws_channel_task_init
aws_channel_new
aws_channel_destroy
aws_channel_shutdown
aws_channel_acquire_hold
aws_channel_release_hold
aws_channel_slot_new
aws_channel_get_event_loop
aws_channel_current_clock_time
aws_channel_fetch_local_object
aws_channel_put_local_object
aws_channel_remove_local_object
aws_channel_acquire_message_from_pool
aws_channel_schedule_task_now
aws_channel_schedule_task_now_serialized
aws_channel_schedule_task_future
aws_channel_set_statistics_handler
aws_channel_thread_is_callers_thread
aws_channel_slot_set_handler
aws_channel_slot_remove
aws_channel_slot_replace
aws_channel_slot_insert_right
aws_channel_slot_insert_end
aws_channel_slot_insert_left
aws_channel_slot_send_message
aws_channel_slot_acquire_max_message_for_write
aws_channel_slot_increment_read_window
aws_channel_slot_on_handler_shutdown_complete
aws_channel_slot_shutdown
aws_channel_slot_downstream_read_window
aws_channel_slot_upstream_message_overhead
aws_channel_handler_destroy
aws_channel_handler_process_read_message
aws_channel_handler_process_write_message
aws_channel_handler_increment_read_window
aws_channel_handler_shutdown
aws_channel_handler_initial_window_size
aws_channel_get_first_slot
aws_channel_trigger_read
aws_overlapped_init
aws_overlapped_reset
aws_overlapped_to_windows_overlapped
aws_event_loop_new_default
aws_event_loop_new_default_with_options
aws_event_loop_destroy
aws_event_loop_init_base
aws_event_loop_clean_up_base
aws_event_loop_fetch_local_object
aws_event_loop_put_local_object
aws_event_loop_remove_local_object
aws_event_loop_run
aws_event_loop_stop
aws_event_loop_register_tick_start
aws_event_loop_register_tick_end
aws_event_loop_get_load_factor
aws_event_loop_wait_for_stop_completion
aws_event_loop_schedule_task_now
aws_event_loop_schedule_task_future
aws_event_loop_cancel_task
aws_event_loop_connect_handle_to_io_completion_port
aws_event_loop_subscribe_to_io_events
aws_event_loop_unsubscribe_from_io_events
aws_event_loop_free_io_event_resources
aws_event_loop_thread_is_callers_thread
aws_event_loop_current_clock_time
aws_event_loop_group_new
aws_event_loop_group_new_pinned_to_cpu_group
aws_event_loop_group_new_default
aws_event_loop_group_new_default_pinned_to_cpu_group
aws_event_loop_group_acquire
aws_event_loop_group_release
aws_event_loop_group_get_loop_at
aws_event_loop_group_get_loop_count
aws_event_loop_group_get_next_loop
aws_host_address_copy
aws_host_address_move
aws_host_address_clean_up
aws_default_dns_resolve
aws_host_resolver_new_default
aws_host_resolver_acquire
aws_host_resolver_release
aws_host_resolver_resolve_host
aws_host_resolver_record_connection_failure
aws_host_resolver_purge_cache
aws_host_resolver_get_host_address_count
aws_host_resolver_add_host_listener
aws_host_resolver_remove_host_listener
aws_memory_pool_init
aws_memory_pool_clean_up
aws_memory_pool_acquire
aws_memory_pool_release
aws_message_pool_init
aws_message_pool_clean_up
aws_message_pool_acquire
aws_message_pool_release
aws_pipe_init
aws_pipe_clean_up_read_end
aws_pipe_clean_up_write_end
aws_pipe_get_read_end_event_loop
aws_pipe_get_write_end_event_loop
aws_pipe_write
aws_pipe_read
aws_pipe_subscribe_to_readable_events
aws_pipe_unsubscribe_from_readable_events
aws_pipe_get_unique_name
aws_pkcs11_lib_new
aws_pkcs11_lib_acquire
aws_pkcs11_lib_release
aws_retry_strategy_acquire
aws_retry_strategy_release
aws_retry_strategy_acquire_retry_token
aws_retry_strategy_schedule_retry
aws_retry_token_record_success
aws_retry_token_acquire
aws_retry_token_release
aws_retry_strategy_new_exponential_backoff
aws_retry_strategy_new_standard
aws_shared_library_init
aws_shared_library_clean_up
aws_shared_library_find_function
aws_socket_handler_new
aws_check_and_init_winsock
aws_winsock_get_connectex_fn
aws_winsock_get_acceptex_fn
aws_socket_init
aws_socket_clean_up
aws_socket_connect
aws_socket_bind
aws_socket_get_bound_address
aws_socket_listen
aws_socket_start_accept
aws_socket_stop_accept
aws_socket_close
aws_socket_shutdown_dir
aws_socket_set_options
aws_socket_assign_to_event_loop
aws_socket_get_event_loop
aws_socket_subscribe_to_readable_events
aws_socket_read
aws_socket_write
aws_socket_get_error
aws_socket_is_open
aws_crt_statistics_socket_init
aws_crt_statistics_socket_cleanup
aws_crt_statistics_socket_reset
aws_crt_statistics_tls_init
aws_crt_statistics_tls_cleanup
aws_crt_statistics_tls_reset
aws_input_stream_acquire
aws_input_stream_release
aws_input_stream_seek
aws_input_stream_read
aws_input_stream_get_status
aws_input_stream_get_length
aws_input_stream_destroy
aws_input_stream_new_from_cursor
aws_input_stream_new_from_file
aws_input_stream_new_from_open_file
aws_tls_ctx_options_init_default_client
aws_tls_ctx_options_clean_up
aws_tls_ctx_options_init_client_mtls_from_path
aws_tls_ctx_options_init_client_mtls
aws_custom_key_op_handler_acquire
aws_custom_key_op_handler_release
aws_custom_key_op_handler_perform_operation
aws_tls_ctx_options_init_client_mtls_with_custom_key_operations
aws_tls_ctx_options_init_client_mtls_with_pkcs11
aws_tls_ctx_options_set_keychain_path
aws_tls_ctx_options_init_default_server_from_path
aws_tls_ctx_options_init_default_server
aws_tls_ctx_options_init_client_mtls_from_system_path
aws_tls_ctx_options_init_default_server_from_system_path
aws_tls_ctx_options_init_client_mtls_pkcs12_from_path
aws_tls_ctx_options_init_client_mtls_pkcs12
aws_tls_ctx_options_init_server_pkcs12_from_path
aws_tls_ctx_options_init_server_pkcs12
aws_tls_ctx_options_set_alpn_list
aws_tls_ctx_options_set_verify_peer
aws_tls_ctx_options_set_minimum_tls_version
aws_tls_ctx_options_override_default_trust_store
aws_tls_ctx_options_override_default_trust_store_from_path
aws_tls_ctx_options_set_extension_data
aws_tls_connection_options_init_from_ctx
aws_tls_connection_options_clean_up
aws_tls_connection_options_copy
aws_tls_connection_options_set_callbacks
aws_tls_connection_options_set_server_name
aws_tls_connection_options_set_alpn_list
aws_tls_is_alpn_available
aws_tls_is_cipher_pref_supported
aws_tls_client_handler_new
aws_tls_server_handler_new
aws_tls_byo_crypto_set_client_setup_options
aws_tls_byo_crypto_set_server_setup_options
aws_tls_alpn_handler_new
aws_tls_client_handler_start_negotiation
aws_tls_server_ctx_new
aws_tls_client_ctx_new
aws_tls_ctx_acquire
aws_tls_ctx_release
aws_tls_handler_write
aws_tls_handler_protocol
aws_tls_handler_server_name
aws_tls_key_operation_complete
aws_tls_key_operation_complete_with_error
aws_tls_key_operation_get_input
aws_tls_key_operation_get_type
aws_tls_key_operation_get_signature_algorithm
aws_tls_key_operation_get_digest_algorithm
aws_channel_setup_client_tls
aws_tls_hash_algorithm_str
aws_tls_signature_algorithm_str
aws_tls_key_operation_type_str
"#;
const TYPES: &str = r#"
aws_io_handle
aws_io_message_type
aws_channel_on_message_write_completed_fn
aws_io_message
aws_io_clock_fn
aws_io_errors
aws_socket
aws_socket_options
aws_socket_endpoint
aws_channel_on_protocol_negotiated_fn
aws_client_bootstrap_on_channel_event_fn
aws_tls_connection_options
aws_event_loop_group
aws_client_bootstrap_shutdown_complete_fn
aws_client_bootstrap
aws_client_bootstrap_options
aws_server_bootstrap_on_accept_channel_setup_fn
aws_server_bootstrap_on_accept_channel_shutdown_fn
aws_server_bootstrap_on_server_listener_destroy_fn
aws_server_bootstrap
aws_socket_channel_bootstrap_options
aws_server_socket_channel_bootstrap_options
aws_channel_direction
aws_channel_on_setup_completed_fn
aws_channel_on_shutdown_completed_fn
aws_channel_slot
aws_channel_task_fn
aws_channel_task
aws_channel_handler_vtable
aws_channel_handler
aws_channel_options
aws_channel
aws_io_event_type
aws_event_loop_on_completion_fn
aws_win32_OVERLAPPED
aws_overlapped
aws_event_loop_on_event_fn
aws_event_loop_vtable
aws_event_loop
aws_event_loop_on_local_object_removed_fn
aws_event_loop_local_object
aws_event_loop_options
aws_new_event_loop_fn
aws_event_loop_group
aws_address_record_type
aws_get_host_address_flags
aws_host_address
aws_on_host_resolved_result_fn
aws_resolve_host_implementation_fn
aws_host_resolution_config
aws_host_listener
aws_host_listener_options
aws_host_resolver_vtable
aws_host_resolver
aws_host_resolver_default_options
aws_host_listener_resolved_address_fn
aws_host_listener_expired_address_fn
aws_host_listener_shutdown_fn
aws_host_listener_options
aws_io_log_subject
aws_memory_pool
aws_message_pool
aws_message_pool_creation_args
aws_pipe_read_end
aws_pipe_write_end
aws_pipe_on_readable_fn
aws_pipe_on_write_completed_fn
aws_pkcs11_lib
aws_pkcs11_lib_behavior
aws_pkcs11_lib_options
aws_retry_strategy_on_retry_token_acquired_fn
aws_retry_strategy_on_retry_ready_fn
aws_retry_error_type
aws_retry_strategy_vtable
aws_retry_strategy
aws_retry_token
aws_exponential_backoff_jitter_mode
aws_exponential_backoff_retry_options
aws_standard_retry_options
aws_shared_library
aws_generic_function
aws_socket_domain
aws_socket_type
aws_socket_options
aws_socket_on_connection_result_fn
aws_socket_on_accept_result_fn
aws_socket_on_write_completed_fn
aws_socket_on_write_completed_fn
aws_socket_on_readable_fn
aws_socket
aws_ms_fn_ptr
aws_crt_io_statistics_category
aws_crt_statistics_socket
aws_crt_statistics_tls
aws_stream_seek_basis
aws_stream_status
aws_input_stream_vtable
aws_input_stream
aws_tls_versions
aws_tls_cipher_pref
aws_tls_hash_algorithm
aws_tls_signature_algorithm
aws_tls_key_operation_type
aws_tls_ctx
aws_tls_on_negotiation_result_fn
aws_tls_on_data_read_fn
aws_tls_on_error_fn
aws_tls_connection_options
aws_tls_key_operation
aws_tls_ctx_options
aws_tls_negotiated_protocol_message
aws_tls_on_protocol_negotiated
aws_channel_handler
aws_tls_negotiation_status
aws_tls_handler_new_fn
aws_tls_client_handler_start_negotiation_fn
aws_tls_byo_crypto_setup_options
aws_custom_key_op_handler_vtable
aws_custom_key_op_handler
aws_tls_ctx_pkcs11_options
"#;

const VARS: &str = "
g_aws_channel_max_fragment_size
";

fn get_include_dir<P: AsRef<Path>>(dir: P) -> PathBuf {
    let mut result = PathBuf::from(dir.as_ref());

    for folder in INCLUDE_PATH.split('/') {
        result.push(folder);
    }

    result
}

fn main() {
    let root = PathBuf::from(var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set"));
    let out_dir = PathBuf::from(var("OUT_DIR").expect("OUT_DIR not set"));

    let src_include_dir = root.join("include");
    let dst_include_dir = out_dir.join("include");
    let src_lib_include_dir = get_include_dir(&src_include_dir);
    let dst_lib_include_dir = get_include_dir(&dst_include_dir);
    let src_include_dir_str = src_include_dir.to_string_lossy();
    let dst_include_dir_str = dst_include_dir.to_string_lossy();
    let src_lib_include_dir_str = src_lib_include_dir.to_string_lossy();
    let dst_lib_include_dir_str = dst_lib_include_dir.to_string_lossy();

    println!("cargo:include={dst_include_dir_str}");
    println!("cargo:rerun-if-changed=include");
    println!("cargo:rerun-if-env-changed=AWS_CRT_PREFIX");

    if let Ok(aws_crt_prefix) = var("AWS_CRT_PREFIX") {
        println!("cargo:rustc-link-search={aws_crt_prefix}/lib");
    }

    for library_name in LINK_LIBS.split('\n') {
        let library_name = library_name.trim();
        if !library_name.is_empty() {
            println!("cargo:rustc-link-lib={library_name}");
        }
    }

    // Copy include files over
    create_dir_all(&dst_lib_include_dir)
        .unwrap_or_else(|e| panic!("Unable to create directory {dst_lib_include_dir_str}: {e}"));

    let mut builder = builder()
        .clang_arg(format!("-I{src_include_dir_str}"))
        .derive_debug(true)
        .derive_default(true)
        .derive_partialeq(true)
        .derive_eq(true)
        .allowlist_recursively(false); // Don't dive into dependent libraries.
    
    for dep in DEP_LIBRARIES.split('\n') {
        let dep = dep.trim();
        if dep.is_empty() {
            continue;
        }

        let dep = String::from(dep).replace('-', "_").to_uppercase();
        let dep_include_dir = PathBuf::from(var(format!("DEP_{dep}_INCLUDE")).unwrap_or_else(|_| panic!("DEP_{dep}_INCLUDE not set")));
        let dep_include_dir_str = dep_include_dir.to_string_lossy();
        builder = builder.clang_arg(format!("-I{dep_include_dir_str}"));
    }

    let mut n_includes = 0;

    for entry in read_dir(&src_lib_include_dir)
        .unwrap_or_else(|e| panic!("Unable to list header files in {src_lib_include_dir_str}: {e}"))
    {
        let entry =
            entry.unwrap_or_else(|e| panic!("Unable to read directory entry in {src_lib_include_dir_str}: {e}"));
        let file_name_string = entry.file_name();
        let src_path = src_lib_include_dir.join(&file_name_string);
        let src_path_str = src_path.to_string_lossy();
        let dst_path = dst_lib_include_dir.join(&file_name_string);

        if entry.file_type().unwrap_or_else(|e| panic!("Unable to read file type of {src_path_str}: {e}")).is_file() {
            // Only include header files ending with .h; ignore .inl.
            let file_name_utf8 = file_name_string.to_str().expect("Unable to convert file name to UTF-8");
            if file_name_utf8.ends_with(".h") {
                builder = builder.header(src_path_str.to_string());
                n_includes += 1;
            }

            // Copy all files to the output directory.
            copy(&src_path, &dst_path).unwrap_or_else(|e| {
                panic!(
                    "Failed to copy from {src_path_str} to {dst_path_str}: {e}",
                    dst_path_str = dst_path.to_string_lossy()
                )
            });
        }
    }

    if n_includes == 0 {
        panic!("No header files found in {src_lib_include_dir_str}");
    }

    for function_pattern in FUNCTIONS.split('\n') {
        let function_pattern = function_pattern.trim();
        if !function_pattern.is_empty() {
            builder = builder.allowlist_function(function_pattern);
        }
    }

    for type_pattern in TYPES.split('\n') {
        let type_pattern = type_pattern.trim();
        if !type_pattern.is_empty() {
            builder = builder.allowlist_type(type_pattern);
        }
    }

    for var_pattern in VARS.split('\n') {
        let var_pattern = var_pattern.trim();
        if !var_pattern.is_empty() {
            builder = builder.allowlist_var(var_pattern);
        }
    }

    let bindings_filename = out_dir.join("bindings.rs");
    let bindings = builder.generate().expect("Unable to generate bindings");
    bindings.write_to_file(&bindings_filename).unwrap_or_else(|e| {
        panic!(
            "Failed to write bindings to {bindings_filename_str}: {e}",
            bindings_filename_str = bindings_filename.to_string_lossy()
        )
    });

    if cfg!(any(target_os = "ios", target_os = "macos")) {
        println!("cargo:rustc-link-arg=-framework");
        println!("cargo:rustc-link-arg=CoreFoundation");
    }
}