├── .clang-format ├── .gitignore ├── Cargo.toml ├── README.md ├── chapter-01 ├── listing_01_python_csv │ ├── input.py │ └── main.py ├── listing_02_rust_csv │ ├── Cargo.toml │ ├── README.md │ └── src │ │ └── main.rs ├── listing_03_java_map │ └── Main.java └── listing_04_rust_map │ ├── Cargo.toml │ └── src │ └── main.rs ├── chapter-02 ├── listing_01_hello_world │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── listing_02_artwork │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── listing_03_admiration │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── listing_04_two_arts │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── listing_05_double_admiration_NO_COMPILE │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── listing_09_double_admiration_ref │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── listing_10_mutability │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── listing_11_view_counter │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── listing_12_use_after_move_NO_COMPILE │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── listing_13_hanging_ref_NO_COMPILE │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── listing_14_read_only_memory │ └── main.c ├── listing_15_large_string_py │ └── main.py ├── listing_16_large_string_rs │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── listing_17_large_string_prealloc │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── listing_18_string_to_ref │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── listing_19_ref_to_string │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── listing_21_fizz_buzz_basic │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── listing_24_fizz_buzz_enum_basic │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── listing_25_fizz_buzz_enum │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── listing_27_fizz_buzz_result │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── listing_29_unit_type_mismatch_NO_COMPILE │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── listing_30_unit_return_explicit │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── listing_32_custom_error │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── listing_34_question_mark │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── listing_35_username_validation │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── listing_36_err_panic │ ├── Cargo.toml │ └── src │ │ └── main.rs └── listing_37_err_unwrap │ ├── Cargo.toml │ └── src │ └── main.rs ├── chapter-03 ├── listing_01_unsafe_iteration │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── listing_02_c_calculator │ └── main.c ├── listing_04_beginning_ffi │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── listing_05_c_code_for_ffi │ └── calculator.c ├── listing_06_most_basic_ffi │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── listing_08_ffi_with_evaluate │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── listing_10_hello_world_display │ ├── Cargo.toml │ └── src │ │ └── main.rs └── listing_13_full_calculator │ ├── Cargo.toml │ ├── main.c │ └── src │ └── lib.rs ├── chapter-04 ├── .gitignore ├── listing_01_module_starter │ ├── Cargo.toml │ ├── module │ │ ├── config │ │ └── ngx_http_calculator.c │ ├── ngx-run │ │ └── nginx.conf │ ├── run │ └── src │ │ └── lib.rs ├── listing_02_build_script_hello │ ├── .gitignore │ ├── Cargo.toml │ ├── build.rs │ └── src │ │ └── main.rs ├── listing_03_build_script_language │ ├── .gitignore │ ├── Cargo.toml │ ├── build.rs │ └── src │ │ └── main.rs ├── listing_04_build_script_include │ ├── .gitignore │ ├── Cargo.toml │ ├── build.rs │ └── src │ │ └── main.rs ├── listing_05_build_script_bindings │ ├── .gitignore │ ├── Cargo.toml │ ├── build.rs │ ├── module │ │ ├── config │ │ └── ngx_http_calculator.c │ ├── ngx-run │ │ └── nginx.conf │ ├── run │ ├── src │ │ └── lib.rs │ └── wrapper.h ├── listing_06_build_script_ngx_prefix │ ├── .gitignore │ ├── Cargo.toml │ ├── build.rs │ ├── module │ │ ├── config │ │ └── ngx_http_calculator.c │ ├── ngx-run │ │ └── nginx.conf │ ├── run │ ├── src │ │ └── lib.rs │ └── wrapper.h ├── listing_07_nginx_handler │ ├── Cargo.toml │ ├── build.rs │ ├── module │ │ ├── config │ │ └── ngx_http_calculator.c │ ├── ngx-run │ │ └── nginx.conf │ ├── run │ ├── src │ │ └── lib.rs │ └── wrapper.h ├── listing_08_request_body │ ├── Cargo.toml │ ├── build.rs │ ├── module │ │ ├── config │ │ └── ngx_http_calculator.c │ ├── ngx-run │ │ └── nginx.conf │ ├── run │ ├── src │ │ └── lib.rs │ └── wrapper.h ├── listing_09_print_vec │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── listing_10_print_vec_fn │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── listing_11_print_vec_fn_dangling_NO_COMPILE │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── listing_12_print_vec_fn_ref_NO_COMPILE │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── listing_13_print_vec_fn_lifetimes │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── listing_14_calculate │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── listing_15_evaluate_expression │ ├── Cargo.toml │ ├── build.rs │ ├── module │ │ ├── config │ │ └── ngx_http_calculator.c │ ├── ngx-run │ │ └── nginx.conf │ ├── run │ ├── src │ │ └── lib.rs │ └── wrapper.h └── listing_16_full_handler │ ├── Cargo.toml │ ├── build.rs │ ├── module │ ├── config │ └── ngx_http_calculator.c │ ├── ngx-run │ └── nginx.conf │ ├── run │ ├── src │ └── lib.rs │ └── wrapper.h ├── chapter-05 ├── listing_01_greeter_start │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── listing_02_greeter_mod_NO_COMPILE │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── listing_03_greeter_use_NO_COMPILE │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── listing_04_greeter_pub │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── listing_05_greeter_mod_files │ ├── Cargo.toml │ └── src │ │ ├── input.rs │ │ ├── main.rs │ │ └── output.rs ├── listing_08_day_kind_NO_COMPILE │ ├── Cargo.toml │ └── src │ │ ├── day_kind.rs │ │ ├── input.rs │ │ ├── main.rs │ │ └── output.rs ├── listing_11_paths │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── listing_12_libsnack │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── listing_13_libsnack_lifecycle_absolute │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── listing_14_libsnack_lifecycle_relative │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── listing_15_libsnack_lifecycle_use │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── listing_20_greeter_day_kind_input │ ├── Cargo.toml │ └── src │ │ ├── day_kind.rs │ │ ├── input.rs │ │ ├── main.rs │ │ └── output.rs ├── listing_21_greeter_day_kind_main │ ├── Cargo.toml │ └── src │ │ ├── day_kind.rs │ │ ├── input.rs │ │ ├── main.rs │ │ └── output.rs ├── listing_22_greeter_day_kind_read_line │ ├── Cargo.toml │ └── src │ │ ├── day_kind.rs │ │ ├── input.rs │ │ ├── main.rs │ │ └── output.rs ├── listing_23_greeter_pub_use │ ├── Cargo.toml │ └── src │ │ ├── day_kind.rs │ │ ├── input.rs │ │ ├── main.rs │ │ └── output.rs ├── listing_27_forest │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── listing_28_forest_pvt_NO_COMPILE │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── listing_29_forest_pub_crate │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── listing_30_nested_parent_visibility │ ├── Cargo.toml │ └── src │ │ └── lib.rs └── listing_31_nested_downward_visibility_doesnt_work_NO_COMPILE │ ├── Cargo.toml │ └── src │ └── lib.rs ├── chapter-06 ├── listing_00_complete │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── listing_01_benching │ ├── Cargo.toml │ ├── benches │ │ └── py-vs-rust.rs │ └── src │ │ └── lib.rs ├── listing_01_python_example │ ├── data.jsonl │ └── main.py ├── listing_02_python_code_finished │ └── main.py ├── listing_03_rust_psuedocode_NO_COMPILE │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── listing_04_json_parser_first_pass_NO_COMPILE │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── listing_05_json_parser_working │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── listing_06_json_parser_wrong_types │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── listing_07_json_summer_rust │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── listing_08_rust_json_lib │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── listing_09_rust_json_empty_pymodule │ ├── .gitignore │ ├── Cargo.toml │ ├── run │ └── src │ │ └── lib.rs ├── listing_10_rust_json_wrapped_pyfunction │ ├── .gitignore │ ├── Cargo.toml │ ├── run │ └── src │ │ └── lib.rs ├── listing_11_python_with_rust │ ├── data.jsonl │ └── main.py ├── listing_12_dev_dependencies_NO_COMPILE │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── listing_13_bench_base │ ├── Cargo.toml │ ├── benches │ │ └── py-vs-rust.rs │ └── src │ │ └── lib.rs └── listing_14_bench_rust_sum │ ├── Cargo.toml │ ├── benches │ └── py-vs-rust.rs │ └── src │ └── lib.rs ├── chapter-07 ├── listing_01_testing │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── listing_02_failing_test │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── listing_03_stdout │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── listing_04_add_fn │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── listing_05_add_fn_doc │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── listing_06_add_fn_doctest │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── listing_07_add_fn_passing_doctest │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── listing_08_rust_json_reminder │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── listing_09_rust_json_tests │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── listing_10_rust_json_raw_string │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── listing_11_more_rust_tests │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── listing_12_python_lib │ └── main.py ├── listing_13_python_lib_fn │ └── main.py ├── listing_14_python_pytest_initial │ ├── main.py │ └── main_test.py ├── listing_15_python_pytest_failing │ ├── main.py │ └── main_test.py ├── listing_16_python_rust │ ├── main.py │ └── main_test.py ├── listing_17_python_rust_monkeypatching │ ├── main.py │ └── main_test.py ├── listing_18_add_bug_to_rust │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── listing_18_python_rust_monkeypatching_with_runner │ ├── main.py │ └── main_test.py └── listing_19_python_rust_randomized │ ├── main.py │ └── main_test.py ├── chapter-08 ├── .gitignore ├── Cargo.toml ├── main-async.py ├── main-mult.py ├── main-single.py ├── main-thread.py ├── main.py ├── main2.py ├── main3.py ├── pyproject.toml ├── requirements.txt └── src │ ├── lib.rs │ └── main.rs ├── chapter-09 └── papers │ ├── Cargo.toml │ ├── index.html │ ├── papers-list │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── index.html │ ├── package-lock.json │ ├── package.json │ ├── public │ │ └── vite.svg │ ├── src │ │ ├── App.css │ │ ├── App.jsx │ │ ├── List.jsx │ │ ├── assets │ │ │ └── react.svg │ │ ├── index.css │ │ └── main.jsx │ └── vite.config.js │ └── src │ └── lib.rs ├── chapter-10 └── journal │ ├── Cargo.toml │ ├── book_search │ ├── .gitignore │ ├── Cargo.toml │ └── src │ │ ├── main.rs │ │ └── main1.bak │ ├── journal_cli │ ├── .gitignore │ ├── Cargo.toml │ └── src │ │ ├── main.rs │ │ ├── main1.bak │ │ ├── main2.bak │ │ └── main3.bak │ ├── paper_search │ ├── .gitignore │ ├── Cargo.toml │ └── src │ │ ├── main.rs │ │ ├── main1.bak │ │ ├── main2.bak │ │ ├── main3.bak │ │ └── main4.bak │ └── paper_search_lib │ ├── .gitignore │ ├── Cargo.toml │ └── src │ └── lib.rs ├── rustfmt.toml └── script ├── build ├── gen-workspace └── reformat-all /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: LLVM 2 | IndentWidth: 2 3 | ContinuationIndentWidth: 2 4 | ColumnLimit: 80 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | **/target/ 3 | **/Cargo.lock 4 | *.class 5 | *.pyc 6 | __pycache__ 7 | *.zip 8 | nginx-1.19.3.tar.gz 9 | nginx-1.19.3 10 | .pytest_cache 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Code from for Refactoring to Rust 2 | 3 | [Get the book Here!][buy_book] 4 | 5 | This repository contains all of the code listings from the new book, 6 | _Refactoring to Rust_. Listings are organized by chapter number and listing 7 | number in the text. Larger examples, which may not be expressible in a single 8 | listing, are given their own directories. 9 | 10 | ## Running the code 11 | 12 | Most of the examples are written in Rust or Python 3. The latest Rust 13 | compiler can be installed by following the instructions at https://rustup.rs/ 14 | 15 | The simpler Rust examples can be tried in a web browser without installing 16 | any software, by visiting https://play.rust-lang.org/ 17 | 18 | **IMPORTANT**: Some sections of the book illustrate compiler errors that 19 | developers new to Rust can commonly make. Listings which have NO_COMPILE in 20 | the directory names are expected to fail to compile. 21 | 22 | [buy_book]: https://www.manning.com/books/refactoring-to-rust?utm_source=mara&utm_medium=affiliate&utm_campaign=book_mara_refactoring_1_6_21&a_aid=mara&a_bid=eedce54d 23 | -------------------------------------------------------------------------------- /chapter-01/listing_01_python_csv/input.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | with open('data.csv', 'w') as f: 4 | for _ in range(1_000_000): 5 | line = ','.join(str(random.randint(0,256)) for _ in range(100)) 6 | f.write(f'{line}\n') -------------------------------------------------------------------------------- /chapter-01/listing_01_python_csv/main.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | 4 | def sum_csv_column(data, column): 5 | sum = 0 6 | 7 | for line in data.split("\n"): 8 | if len(line) == 0: 9 | continue 10 | 11 | value_str = line.split(",")[column] 12 | sum += int(value_str) 13 | 14 | return sum 15 | 16 | 17 | with open('data.csv') as f: 18 | data = f.read() 19 | 20 | start = time.time() 21 | value = sum_csv_column(data, 10) 22 | end = time.time() 23 | 24 | print(end - start) 25 | 26 | print(value) 27 | -------------------------------------------------------------------------------- /chapter-01/listing_02_rust_csv/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-01-listing-02" 3 | version = "0.1.0" 4 | authors = ["Lily Mara "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /chapter-01/listing_02_rust_csv/README.md: -------------------------------------------------------------------------------- 1 | # Listing 01.02 2 | 3 | This listing has a dependency on a CSV data file, which can be generated by 4 | running `chapter-01/listing_01/input.py`. 5 | -------------------------------------------------------------------------------- /chapter-01/listing_02_rust_csv/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::fs::File; 2 | use std::io::prelude::*; 3 | use std::time::Instant; 4 | 5 | fn main() { 6 | let mut f = File::open("data.csv").unwrap(); 7 | let mut s = String::new(); 8 | 9 | f.read_to_string(&mut s).unwrap(); 10 | 11 | let start = Instant::now(); 12 | let sum = sum_csv_column(&s, 10); 13 | let end = Instant::now(); 14 | 15 | println!("{:?}", end - start); 16 | println!("{:?}", sum); 17 | } 18 | 19 | fn sum_csv_column(data: &str, column: usize) -> i64 { 20 | let mut sum = 0; 21 | 22 | for line in data.lines() { 23 | if line.len() == 0 { 24 | continue; 25 | } 26 | 27 | let value_str = line.split(",").nth(column).unwrap(); 28 | sum += value_str.parse::().unwrap(); 29 | } 30 | 31 | sum 32 | } 33 | -------------------------------------------------------------------------------- /chapter-01/listing_03_java_map/Main.java: -------------------------------------------------------------------------------- 1 | import java.util.ArrayList; 2 | import java.util.HashMap; 3 | 4 | public class Main { 5 | public static void main(String[] args) { 6 | HashMap> map = 7 | new HashMap>(); 8 | ArrayList list = new ArrayList(); 9 | 10 | list.add(4); 11 | list.add(10); 12 | 13 | map.put(1, list); 14 | } 15 | } -------------------------------------------------------------------------------- /chapter-01/listing_04_rust_map/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-01-listing-04" 3 | version = "0.1.0" 4 | authors = ["Lily Mara "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /chapter-01/listing_04_rust_map/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | fn main() { 4 | let mut map = HashMap::new(); 5 | map.insert(1, vec![4, 10]); 6 | } 7 | -------------------------------------------------------------------------------- /chapter-02/listing_01_hello_world/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-02-listing-01" 3 | version = "0.1.0" 4 | authors = ["Lily Mara "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /chapter-02/listing_01_hello_world/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | println!("Hello, world!"); 3 | } 4 | -------------------------------------------------------------------------------- /chapter-02/listing_02_artwork/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-02-listing-02" 3 | version = "0.1.0" 4 | authors = ["Lily Mara "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /chapter-02/listing_02_artwork/src/main.rs: -------------------------------------------------------------------------------- 1 | struct Artwork { 2 | name: String, 3 | } 4 | 5 | fn main() { 6 | let art1 = Artwork { 7 | name: "Boy with Apple".to_string(), 8 | }; 9 | } 10 | -------------------------------------------------------------------------------- /chapter-02/listing_03_admiration/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-02-listing-03" 3 | version = "0.1.0" 4 | authors = ["Lily Mara "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /chapter-02/listing_03_admiration/src/main.rs: -------------------------------------------------------------------------------- 1 | struct Artwork { 2 | name: String, 3 | } 4 | 5 | fn admire_art(art: Artwork) { 6 | println!("Wow, {} really makes you think.", art.name,); 7 | } 8 | 9 | fn main() { 10 | let art1 = Artwork { 11 | name: "La Trahison des images".to_string(), 12 | }; 13 | admire_art(art1); 14 | } 15 | -------------------------------------------------------------------------------- /chapter-02/listing_04_two_arts/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-02-listing-04" 3 | version = "0.1.0" 4 | authors = ["Lily Mara "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /chapter-02/listing_04_two_arts/src/main.rs: -------------------------------------------------------------------------------- 1 | struct Artwork { 2 | name: String, 3 | } 4 | 5 | fn admire_art(art: Artwork) { 6 | println!("Wow, {} really makes you think.", art.name); 7 | } 8 | 9 | fn main() { 10 | let art1 = Artwork { 11 | name: "Las dos Fridas".to_string(), 12 | }; 13 | let art2 = Artwork { 14 | name: "The Persistence of Memory".to_string(), 15 | }; 16 | 17 | admire_art(art1); 18 | admire_art(art2); 19 | } 20 | -------------------------------------------------------------------------------- /chapter-02/listing_05_double_admiration_NO_COMPILE/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-02-listing-05" 3 | version = "0.1.0" 4 | authors = ["Lily Mara "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /chapter-02/listing_05_double_admiration_NO_COMPILE/src/main.rs: -------------------------------------------------------------------------------- 1 | struct Artwork { 2 | name: String, 3 | } 4 | 5 | fn admire_art(art: Artwork) { 6 | println!("Wow, {} really makes you think.", art.name); 7 | } 8 | 9 | fn main() { 10 | let art1 = Artwork { 11 | name: "The Ordeal of Owain".to_string(), 12 | }; 13 | 14 | admire_art(art1); 15 | admire_art(art1); 16 | } 17 | -------------------------------------------------------------------------------- /chapter-02/listing_09_double_admiration_ref/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-02-listing-09" 3 | version = "0.1.0" 4 | authors = ["Lily Mara "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /chapter-02/listing_09_double_admiration_ref/src/main.rs: -------------------------------------------------------------------------------- 1 | struct Artwork { 2 | name: String, 3 | } 4 | 5 | fn admire_art(art: &Artwork) { 6 | println!("Wow, {} really makes you think.", art.name); 7 | } 8 | 9 | fn main() { 10 | let art1 = Artwork { 11 | name: "The Ordeal of Owain".to_string(), 12 | }; 13 | 14 | admire_art(&art1); 15 | admire_art(&art1); 16 | } 17 | -------------------------------------------------------------------------------- /chapter-02/listing_10_mutability/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-02-listing-10" 3 | version = "0.1.0" 4 | authors = ["Lily Mara "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /chapter-02/listing_10_mutability/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let x = 0; 3 | let mut y = 0; 4 | 5 | println!("x={}, y={}", x, y); 6 | 7 | y += 10; 8 | println!("x={}, y={}", x, y); 9 | } 10 | -------------------------------------------------------------------------------- /chapter-02/listing_11_view_counter/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-02-listing-11" 3 | version = "0.1.0" 4 | authors = ["Lily Mara "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /chapter-02/listing_11_view_counter/src/main.rs: -------------------------------------------------------------------------------- 1 | struct Artwork { 2 | view_count: i32, 3 | name: String, 4 | } 5 | 6 | fn admire_art(art: &mut Artwork) { 7 | println!("{} people have seen {} today!", art.view_count, art.name); 8 | art.view_count += 1; 9 | } 10 | 11 | fn main() { 12 | let mut art1 = Artwork { 13 | view_count: 0, 14 | name: "".to_string(), 15 | }; 16 | 17 | admire_art(&mut art1); 18 | admire_art(&mut art1); 19 | } 20 | -------------------------------------------------------------------------------- /chapter-02/listing_12_use_after_move_NO_COMPILE/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-02-listing-12" 3 | version = "0.1.0" 4 | authors = ["Lily Mara "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /chapter-02/listing_12_use_after_move_NO_COMPILE/src/main.rs: -------------------------------------------------------------------------------- 1 | struct Artwork { 2 | name: String, 3 | } 4 | 5 | fn admire_art(art: Artwork) { 6 | println!("Wow, {} really makes you think.", art.name); 7 | } 8 | 9 | fn main() { 10 | let art1 = Artwork { 11 | name: "Man on Fire".to_string(), 12 | }; 13 | 14 | let borrowed_art = &art1; 15 | 16 | admire_art(art1); 17 | 18 | println!("I really enjoy {}", borrowed_art.name); 19 | } 20 | -------------------------------------------------------------------------------- /chapter-02/listing_13_hanging_ref_NO_COMPILE/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-02-listing-13" 3 | version = "0.1.0" 4 | authors = ["Lily Mara "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /chapter-02/listing_13_hanging_ref_NO_COMPILE/src/main.rs: -------------------------------------------------------------------------------- 1 | struct Artwork { 2 | name: String, 3 | } 4 | 5 | fn build_art() -> &Artwork { 6 | let art = Artwork { 7 | name: "La Liberté guidant le peuple".to_string(), 8 | }; 9 | 10 | &art 11 | } 12 | 13 | fn main() { 14 | let art = build_art(); 15 | } 16 | -------------------------------------------------------------------------------- /chapter-02/listing_14_read_only_memory/main.c: -------------------------------------------------------------------------------- 1 | int main(void) { 2 | char *str = "hello, world!"; 3 | str[0] = '!'; 4 | return 0; 5 | } -------------------------------------------------------------------------------- /chapter-02/listing_15_large_string_py/main.py: -------------------------------------------------------------------------------- 1 | x = "" 2 | 3 | for i in range(0, 10_000_000): 4 | x += "." 5 | 6 | print(len(x)) -------------------------------------------------------------------------------- /chapter-02/listing_16_large_string_rs/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-02-listing-16" 3 | version = "0.1.0" 4 | authors = ["Lily Mara "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /chapter-02/listing_16_large_string_rs/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let mut x = String::new(); 3 | 4 | for i in 0..10_000_000 { 5 | x.push('.'); 6 | } 7 | 8 | println!("{}", x.len()); 9 | } 10 | -------------------------------------------------------------------------------- /chapter-02/listing_17_large_string_prealloc/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-02-listing-17" 3 | version = "0.1.0" 4 | authors = ["Lily Mara "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /chapter-02/listing_17_large_string_prealloc/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let mut x = String::with_capacity(10_000_000); 3 | for i in 0..10_000_000 { 4 | x.push('.'); 5 | } 6 | 7 | println!("{}", x.len()); 8 | } 9 | -------------------------------------------------------------------------------- /chapter-02/listing_18_string_to_ref/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-02-listing-18" 3 | version = "0.1.0" 4 | authors = ["Lily Mara "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /chapter-02/listing_18_string_to_ref/src/main.rs: -------------------------------------------------------------------------------- 1 | fn print_admiration(name: &str) { 2 | println!("Wow, {} really makes you think.", name,); 3 | } 4 | 5 | fn main() { 6 | let value = String::new(); 7 | print_admiration(value.as_str()); 8 | } 9 | -------------------------------------------------------------------------------- /chapter-02/listing_19_ref_to_string/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-02-listing-19" 3 | version = "0.1.0" 4 | authors = ["Lily Mara "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /chapter-02/listing_19_ref_to_string/src/main.rs: -------------------------------------------------------------------------------- 1 | fn print_admiration(name: String) { 2 | println!("Wow, {} really makes you think.", name); 3 | } 4 | 5 | fn main() { 6 | let value = "Artwork"; 7 | print_admiration(value.to_string()); 8 | } 9 | -------------------------------------------------------------------------------- /chapter-02/listing_21_fizz_buzz_basic/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-02-listing-21" 3 | version = "0.1.0" 4 | authors = ["Lily Mara "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /chapter-02/listing_21_fizz_buzz_basic/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | for i in 1..101 { 3 | print_fizzbuzz(i); 4 | } 5 | } 6 | 7 | fn print_fizzbuzz(x: i32) { // <1> 8 | println!("{}", fizzbuzz(x)); 9 | } 10 | 11 | fn fizzbuzz(x: i32) -> String { 12 | if x % 3 == 0 && x % 5 == 0 { 13 | String::from("FizzBuzz") 14 | } else if x % 3 == 0 { 15 | String::from("Fizz") 16 | } else if x % 5 == 0 { 17 | String::from("Buzz") 18 | } else { 19 | format!("{}", x) // <2> 20 | } 21 | } -------------------------------------------------------------------------------- /chapter-02/listing_24_fizz_buzz_enum_basic/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-02-listing-24" 3 | version = "0.1.0" 4 | authors = ["Lily Mara "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /chapter-02/listing_24_fizz_buzz_enum_basic/src/main.rs: -------------------------------------------------------------------------------- 1 | enum FizzBuzzValue { 2 | Fizz, 3 | Buzz, 4 | FizzBuzz, 5 | NotDivisible, 6 | } 7 | 8 | fn main() { 9 | for i in 1..101 { 10 | print_fizzbuzz(i); 11 | } 12 | } 13 | 14 | fn print_fizzbuzz(x: i32) { 15 | match fizzbuzz(x) { 16 | FizzBuzzValue::FizzBuzz => { 17 | // <1> 18 | println!("FizzBuzz"); 19 | } 20 | FizzBuzzValue::Fizz => { 21 | println!("Fizz"); 22 | } 23 | FizzBuzzValue::Buzz => { 24 | println!("Buzz"); 25 | } 26 | FizzBuzzValue::NotDivisible => { 27 | println!("{}", x); 28 | } 29 | } 30 | } 31 | 32 | fn fizzbuzz(x: i32) -> FizzBuzzValue { 33 | if x % 3 == 0 && x % 5 == 0 { 34 | FizzBuzzValue::FizzBuzz 35 | } else if x % 3 == 0 { 36 | FizzBuzzValue::Fizz 37 | } else if x % 5 == 0 { 38 | FizzBuzzValue::Buzz 39 | } else { 40 | FizzBuzzValue::NotDivisible 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /chapter-02/listing_25_fizz_buzz_enum/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-02-listing-25" 3 | version = "0.1.0" 4 | authors = ["Lily Mara "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /chapter-02/listing_25_fizz_buzz_enum/src/main.rs: -------------------------------------------------------------------------------- 1 | enum FizzBuzzValue { 2 | Fizz, 3 | Buzz, 4 | FizzBuzz, 5 | NotDivisible(i32), // <1> 6 | } 7 | 8 | fn main() { 9 | for i in 1..101 { 10 | print_fizzbuzz(i); 11 | } 12 | } 13 | 14 | fn print_fizzbuzz(x: i32) { 15 | match fizzbuzz(x) { 16 | FizzBuzzValue::FizzBuzz => { 17 | println!("FizzBuzz"); 18 | } 19 | FizzBuzzValue::Fizz => { 20 | println!("Fizz"); 21 | } 22 | FizzBuzzValue::Buzz => { 23 | println!("Buzz"); 24 | } 25 | FizzBuzzValue::NotDivisible(num) => { 26 | // <2> 27 | println!("{}", num); 28 | } 29 | } 30 | } 31 | 32 | fn fizzbuzz(x: i32) -> FizzBuzzValue { 33 | if x % 3 == 0 && x % 5 == 0 { 34 | FizzBuzzValue::FizzBuzz 35 | } else if x % 3 == 0 { 36 | FizzBuzzValue::Fizz 37 | } else if x % 5 == 0 { 38 | FizzBuzzValue::Buzz 39 | } else { 40 | FizzBuzzValue::NotDivisible(x) // <3> 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /chapter-02/listing_27_fizz_buzz_result/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-02-listing-27" 3 | version = "0.1.0" 4 | authors = ["Lily Mara "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /chapter-02/listing_27_fizz_buzz_result/src/main.rs: -------------------------------------------------------------------------------- 1 | enum FizzBuzzValue { 2 | Fizz, 3 | Buzz, 4 | FizzBuzz, 5 | NotDivisible(i32), 6 | } 7 | 8 | fn main() { 9 | for i in 1..101 { 10 | match print_fizzbuzz(i) { 11 | Ok(()) => {} 12 | Err(e) => { 13 | eprintln!("Error: {}", e); // <1> 14 | return; 15 | } 16 | } 17 | } 18 | } 19 | 20 | fn print_fizzbuzz(x: i32) -> Result<(), &'static str> { 21 | // <2> 22 | match fizzbuzz(x) { 23 | Ok(result) => { 24 | // <3> 25 | match result { 26 | FizzBuzzValue::FizzBuzz => { 27 | println!("FizzBuzz"); 28 | } 29 | FizzBuzzValue::Fizz => { 30 | println!("Fizz"); 31 | } 32 | FizzBuzzValue::Buzz => { 33 | println!("Buzz"); 34 | } 35 | FizzBuzzValue::NotDivisible(num) => { 36 | println!("{}", num); 37 | } 38 | } 39 | 40 | Ok(()) 41 | } 42 | Err(e) => Err(e), 43 | } 44 | } 45 | 46 | fn fizzbuzz(x: i32) -> Result { 47 | if x < 0 { 48 | Err("Provided number must be positive!") 49 | } else if x % 3 == 0 && x % 5 == 0 { 50 | Ok(FizzBuzzValue::FizzBuzz) // <4> 51 | } else if x % 3 == 0 { 52 | Ok(FizzBuzzValue::Fizz) 53 | } else if x % 5 == 0 { 54 | Ok(FizzBuzzValue::Buzz) 55 | } else { 56 | Ok(FizzBuzzValue::NotDivisible(x)) 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /chapter-02/listing_29_unit_type_mismatch_NO_COMPILE/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-02-listing-29" 3 | version = "0.1.0" 4 | authors = ["Lily Mara "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /chapter-02/listing_29_unit_type_mismatch_NO_COMPILE/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let x: String = (); 3 | println!("{}", x); 4 | } 5 | -------------------------------------------------------------------------------- /chapter-02/listing_30_unit_return_explicit/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-02-listing-30" 3 | version = "0.1.0" 4 | authors = ["Lily Mara "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /chapter-02/listing_30_unit_return_explicit/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | foo(); 3 | bar(); 4 | baz(); 5 | } 6 | 7 | fn foo() { // <1> 8 | println!("Hello!"); 9 | } 10 | 11 | fn bar() -> () { // <2> 12 | println!("Hello!"); 13 | } 14 | 15 | fn baz() -> () { 16 | println!("Hello!"); 17 | () // <3> 18 | } 19 | -------------------------------------------------------------------------------- /chapter-02/listing_32_custom_error/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-02-listing-32" 3 | version = "0.1.0" 4 | authors = ["Lily Mara "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /chapter-02/listing_32_custom_error/src/main.rs: -------------------------------------------------------------------------------- 1 | enum FizzBuzzValue { 2 | Fizz, 3 | Buzz, 4 | FizzBuzz, 5 | NotDivisible(i32), 6 | } 7 | 8 | enum Error { 9 | GotNegative, 10 | } 11 | 12 | fn main() { 13 | for i in 1..101 { 14 | match print_fizzbuzz(i) { 15 | Ok(()) => {} 16 | Err(e) => match e { 17 | Error::GotNegative => { 18 | eprintln!("Error: Fizz Buzz only supports positive numbers!"); 19 | return; 20 | } 21 | }, 22 | } 23 | } 24 | } 25 | 26 | fn print_fizzbuzz(x: i32) -> Result<(), Error> { 27 | match fizzbuzz(x) { 28 | Ok(result) => { 29 | match result { 30 | FizzBuzzValue::FizzBuzz => { 31 | println!("FizzBuzz"); 32 | } 33 | FizzBuzzValue::Fizz => { 34 | println!("Fizz"); 35 | } 36 | FizzBuzzValue::Buzz => { 37 | println!("Buzz"); 38 | } 39 | FizzBuzzValue::NotDivisible(num) => { 40 | println!("{}", num); 41 | } 42 | } 43 | 44 | Ok(()) 45 | } 46 | Err(e) => Err(e), 47 | } 48 | } 49 | 50 | fn fizzbuzz(x: i32) -> Result { 51 | if x < 0 { 52 | Err(Error::GotNegative) 53 | } else if x % 3 == 0 && x % 5 == 0 { 54 | Ok(FizzBuzzValue::FizzBuzz) 55 | } else if x % 3 == 0 { 56 | Ok(FizzBuzzValue::Fizz) 57 | } else if x % 5 == 0 { 58 | Ok(FizzBuzzValue::Buzz) 59 | } else { 60 | Ok(FizzBuzzValue::NotDivisible(x)) 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /chapter-02/listing_34_question_mark/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-02-listing-34" 3 | version = "0.1.0" 4 | authors = ["Lily Mara "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /chapter-02/listing_34_question_mark/src/main.rs: -------------------------------------------------------------------------------- 1 | enum FizzBuzzValue { 2 | Fizz, 3 | Buzz, 4 | FizzBuzz, 5 | NotDivisible(i32), 6 | } 7 | 8 | enum Error { 9 | GotNegative, 10 | } 11 | 12 | fn main() { 13 | for i in 1..101 { 14 | match print_fizzbuzz(i) { 15 | Ok(()) => {} 16 | Err(e) => match e { 17 | Error::GotNegative => { 18 | eprintln!("Error: Fizz Buzz only supports positive numbers!"); 19 | return; 20 | } 21 | }, 22 | } 23 | } 24 | } 25 | 26 | fn print_fizzbuzz(x: i32) -> Result<(), Error> { 27 | match fizzbuzz(x)? { 28 | // <1> 29 | FizzBuzzValue::FizzBuzz => { 30 | println!("FizzBuzz"); 31 | } 32 | FizzBuzzValue::Fizz => { 33 | println!("Fizz"); 34 | } 35 | FizzBuzzValue::Buzz => { 36 | println!("Buzz"); 37 | } 38 | FizzBuzzValue::NotDivisible(num) => { 39 | println!("{}", num); 40 | } 41 | } 42 | 43 | Ok(()) 44 | } 45 | 46 | fn fizzbuzz(x: i32) -> Result { 47 | if x < 0 { 48 | Err(Error::GotNegative) 49 | } else if x % 3 == 0 && x % 5 == 0 { 50 | Ok(FizzBuzzValue::FizzBuzz) 51 | } else if x % 3 == 0 { 52 | Ok(FizzBuzzValue::Fizz) 53 | } else if x % 5 == 0 { 54 | Ok(FizzBuzzValue::Buzz) 55 | } else { 56 | Ok(FizzBuzzValue::NotDivisible(x)) 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /chapter-02/listing_35_username_validation/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-02-listing-35" 3 | version = "0.1.0" 4 | authors = ["Lily Mara "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /chapter-02/listing_35_username_validation/src/main.rs: -------------------------------------------------------------------------------- 1 | enum UsernameError { 2 | NotLowercase, 3 | NotUnique, 4 | } 5 | 6 | fn main() { 7 | match validate_username("user1") { 8 | Ok(()) => println!("Valid username"), 9 | Err(UsernameError::NotLowercase) => println!("Username must be lowercase"), 10 | Err(UsernameError::NotUnique) => println!("Username already exists"), 11 | } 12 | } 13 | 14 | fn validate_username(username: &str) -> Result<(), UsernameError> { 15 | validate_lowercase(username).map_err(|_| UsernameError::NotLowercase)?; 16 | validate_unique(username).map_err(|_| UsernameError::NotUnique)?; 17 | 18 | Ok(()) 19 | } 20 | 21 | fn validate_lowercase(username: &str) -> Result<(), ()> { 22 | Ok(()) 23 | } 24 | 25 | fn validate_unique(username: &str) -> Result<(), ()> { 26 | Ok(()) 27 | } 28 | -------------------------------------------------------------------------------- /chapter-02/listing_36_err_panic/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-02-listing-36" 3 | version = "0.1.0" 4 | authors = ["Lily Mara "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /chapter-02/listing_36_err_panic/src/main.rs: -------------------------------------------------------------------------------- 1 | enum FizzBuzzValue { 2 | Fizz, 3 | Buzz, 4 | FizzBuzz, 5 | NotDivisible(i32), 6 | } 7 | 8 | enum Error { 9 | GotNegative, 10 | } 11 | 12 | fn main() { 13 | print_fizzbuzz(-1); 14 | } 15 | 16 | fn print_fizzbuzz(x: i32) { 17 | match fizzbuzz(x) { 18 | Ok(result) => match result { 19 | FizzBuzzValue::FizzBuzz => { 20 | println!("FizzBuzz"); 21 | } 22 | FizzBuzzValue::Fizz => { 23 | println!("Fizz"); 24 | } 25 | FizzBuzzValue::Buzz => { 26 | println!("Buzz"); 27 | } 28 | FizzBuzzValue::NotDivisible(num) => { 29 | println!("{}", num); 30 | } 31 | }, 32 | Err(Error::GotNegative) => { 33 | panic!("Got a negative number for fizzbuzz: {}", x); 34 | } 35 | } 36 | } 37 | 38 | fn fizzbuzz(x: i32) -> Result { 39 | if x < 0 { 40 | Err(Error::GotNegative) 41 | } else if x % 3 == 0 && x % 5 == 0 { 42 | Ok(FizzBuzzValue::FizzBuzz) 43 | } else if x % 3 == 0 { 44 | Ok(FizzBuzzValue::Fizz) 45 | } else if x % 5 == 0 { 46 | Ok(FizzBuzzValue::Buzz) 47 | } else { 48 | Ok(FizzBuzzValue::NotDivisible(x)) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /chapter-02/listing_37_err_unwrap/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-02-listing-37" 3 | version = "0.1.0" 4 | authors = ["Lily Mara "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /chapter-02/listing_37_err_unwrap/src/main.rs: -------------------------------------------------------------------------------- 1 | enum FizzBuzzValue { 2 | Fizz, 3 | Buzz, 4 | FizzBuzz, 5 | NotDivisible(i32), 6 | } 7 | 8 | #[derive(Debug)] 9 | enum Error { 10 | GotNegative, 11 | } 12 | 13 | fn main() { 14 | print_fizzbuzz(-1); 15 | } 16 | 17 | fn print_fizzbuzz(x: i32) { 18 | match fizzbuzz(x).unwrap() { 19 | FizzBuzzValue::FizzBuzz => { 20 | println!("FizzBuzz"); 21 | } 22 | FizzBuzzValue::Fizz => { 23 | println!("Fizz"); 24 | } 25 | FizzBuzzValue::Buzz => { 26 | println!("Buzz"); 27 | } 28 | FizzBuzzValue::NotDivisible(num) => { 29 | println!("{}", num); 30 | } 31 | } 32 | } 33 | 34 | fn fizzbuzz(x: i32) -> Result { 35 | if x < 0 { 36 | Err(Error::GotNegative) 37 | } else if x % 3 == 0 && x % 5 == 0 { 38 | Ok(FizzBuzzValue::FizzBuzz) 39 | } else if x % 3 == 0 { 40 | Ok(FizzBuzzValue::Fizz) 41 | } else if x % 5 == 0 { 42 | Ok(FizzBuzzValue::Buzz) 43 | } else { 44 | Ok(FizzBuzzValue::NotDivisible(x)) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /chapter-03/listing_01_unsafe_iteration/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-03-listing-01" 3 | version = "0.1.0" 4 | authors = ["Lily Mara "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /chapter-03/listing_01_unsafe_iteration/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let data: Vec = vec![5, 10, 15, 20]; 3 | 4 | read_u8_slice(data.as_ptr(), data.len()); 5 | } 6 | 7 | fn read_u8_slice(slice_p: *const u8, length: usize) { 8 | for index in 0..length { 9 | unsafe { 10 | println!("slice[{}] = {}", index, *slice_p.offset(index as isize)); 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /chapter-03/listing_02_c_calculator/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int solve(char *line, int *solution); 5 | 6 | int main() { 7 | char line[100]; // <1> 8 | int solution; 9 | 10 | while (1) { 11 | printf("> "); 12 | if (fgets(line, 100, stdin) == NULL) { // <2> 13 | return 0; 14 | } 15 | 16 | if (solve(line, &solution)) { 17 | continue; 18 | } 19 | 20 | printf("%d\n", solution); 21 | } 22 | 23 | return 0; 24 | } 25 | 26 | int solve(char *line, int *solution) { // <3> 27 | int num1, num2; 28 | char operator; 29 | 30 | int values_read = sscanf(line, "%d %d %c", &num1, &num2, &operator); // <4> 31 | if (values_read != 3) { 32 | return 1; 33 | } 34 | 35 | switch (operator) { 36 | case '+': 37 | *solution = num1 + num2; // <5> 38 | return 0; 39 | case '-': 40 | *solution = num1 - num2; 41 | return 0; 42 | case '*': 43 | *solution = num1 * num2; 44 | return 0; 45 | case '/': 46 | *solution = num1 / num2; 47 | return 0; 48 | } 49 | 50 | return 1; 51 | } -------------------------------------------------------------------------------- /chapter-03/listing_04_beginning_ffi/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-03-listing-04" 3 | version = "0.1.0" 4 | authors = ["Lily Mara "] 5 | edition = "2018" 6 | # See more keys and their definitions at 7 | # https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | libc = "0.2.80" 11 | -------------------------------------------------------------------------------- /chapter-03/listing_04_beginning_ffi/src/lib.rs: -------------------------------------------------------------------------------- 1 | use libc::{c_char, c_int}; 2 | 3 | fn solve(line: *const c_char, solution: *mut c_int) -> c_int { 4 | 0 5 | } 6 | -------------------------------------------------------------------------------- /chapter-03/listing_05_c_code_for_ffi/calculator.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int solve(char *line, int *solution); // <1> 5 | 6 | int main() { 7 | char line[100]; 8 | int solution; 9 | 10 | while (1) { 11 | printf("> "); 12 | if (fgets(line, 100, stdin) == NULL) { 13 | return 0; 14 | } 15 | 16 | if (solve(line, &solution)) { 17 | continue; 18 | } 19 | 20 | printf("%d\n", solution); 21 | } 22 | return 0; 23 | } -------------------------------------------------------------------------------- /chapter-03/listing_06_most_basic_ffi/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-03-listing-06" 3 | version = "0.1.0" 4 | authors = ["Lily Mara "] 5 | edition = "2018" 6 | # See more keys and their definitions at 7 | # https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [lib] 10 | crate-type = ["cdylib"] 11 | 12 | [dependencies] 13 | libc = "0.2.80" 14 | -------------------------------------------------------------------------------- /chapter-03/listing_06_most_basic_ffi/src/lib.rs: -------------------------------------------------------------------------------- 1 | use libc::{c_char, c_int}; 2 | 3 | #[no_mangle] 4 | pub extern "C" fn solve(line: *const c_char, solution: *mut c_int) -> c_int { 5 | 0 6 | } 7 | -------------------------------------------------------------------------------- /chapter-03/listing_08_ffi_with_evaluate/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-03-listing-08" 3 | version = "0.1.0" 4 | authors = ["Lily Mara "] 5 | edition = "2018" 6 | # See more keys and their definitions at 7 | # https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [lib] 10 | crate-type = ["cdylib"] 11 | 12 | [dependencies] 13 | libc = "0.2.80" 14 | -------------------------------------------------------------------------------- /chapter-03/listing_08_ffi_with_evaluate/src/lib.rs: -------------------------------------------------------------------------------- 1 | use libc::{c_char, c_int}; 2 | use std::ffi::CStr; 3 | 4 | #[no_mangle] 5 | pub extern "C" fn solve(line: *const c_char, solution: *mut c_int) -> c_int { 6 | if line.is_null() || solution.is_null() { 7 | return 1; 8 | } 9 | let c_str = unsafe { CStr::from_ptr(line) }; 10 | let r_str = match c_str.to_str() { 11 | Ok(s) => s, 12 | Err(e) => { 13 | eprintln!("UTF-8 Error: {}", e); 14 | return 1; 15 | } 16 | }; 17 | match evaluate(r_str) { 18 | Ok(value) => { 19 | unsafe { 20 | *solution = value as c_int; 21 | } 22 | 0 23 | } 24 | Err(e) => { 25 | eprintln!("Error: {}", e); 26 | 1 27 | } 28 | } 29 | } 30 | 31 | fn evaluate(problem: &str) -> Result { 32 | Ok(1) 33 | } 34 | -------------------------------------------------------------------------------- /chapter-03/listing_10_hello_world_display/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-03-listing-10" 3 | version = "0.1.0" 4 | authors = ["Lily Mara "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /chapter-03/listing_10_hello_world_display/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::{Display, Formatter}; 2 | 3 | struct Hello {} 4 | 5 | impl Display for Hello { // <1> 6 | fn fmt(&self, f: &mut Formatter) -> std::fmt::Result { // <2> 7 | write!(f, "Hello world!") // <3> 8 | } 9 | } 10 | 11 | fn main() { 12 | let x = Hello {}; 13 | println!("{}", x); // <4> 14 | } -------------------------------------------------------------------------------- /chapter-03/listing_13_full_calculator/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-03-listing-13" 3 | version = "0.1.0" 4 | authors = ["Lily Mara "] 5 | edition = "2018" 6 | # See more keys and their definitions at 7 | # https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [lib] 10 | crate-type = ["cdylib"] 11 | 12 | [dependencies] 13 | libc = "0.2.80" 14 | -------------------------------------------------------------------------------- /chapter-03/listing_13_full_calculator/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int solve(char *line, int *solution); // <1> 5 | 6 | int main() { 7 | char line[100]; 8 | int solution; 9 | 10 | while (1) { 11 | printf("> "); 12 | if (fgets(line, 100, stdin) == NULL) { 13 | return 0; 14 | } 15 | 16 | if (solve(line, &solution)) { 17 | continue; 18 | } 19 | 20 | printf("%d\n", solution); 21 | } 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /chapter-03/listing_13_full_calculator/src/lib.rs: -------------------------------------------------------------------------------- 1 | use libc::{c_char, c_int}; 2 | use std::collections::VecDeque; 3 | use std::ffi::CStr; 4 | use std::fmt::{Display, Formatter}; 5 | 6 | #[no_mangle] 7 | pub extern "C" fn solve(line: *const c_char, solution: *mut c_int) -> c_int { 8 | if line.is_null() || solution.is_null() { 9 | return 1; 10 | } 11 | 12 | let c_str = unsafe { CStr::from_ptr(line) }; 13 | let r_str = match c_str.to_str() { 14 | Ok(s) => s, 15 | Err(e) => { 16 | eprintln!("UTF-8 Error: {}", e); 17 | return 1; 18 | } 19 | }; 20 | 21 | match evaluate(r_str) { 22 | Ok(value) => { 23 | unsafe { 24 | *solution = value as c_int; 25 | } 26 | 0 27 | } 28 | Err(e) => { 29 | eprintln!("Error: {}", e); 30 | 1 31 | } 32 | } 33 | } 34 | 35 | enum Error { 36 | InvalidNumber, 37 | PopFromEmptyStack, 38 | } 39 | 40 | impl Display for Error { 41 | fn fmt(&self, f: &mut Formatter) -> std::fmt::Result { 42 | match self { 43 | Error::InvalidNumber => write!(f, "Not a valid number or operator"), 44 | Error::PopFromEmptyStack => write!(f, "Tried to operate on empty stack"), 45 | } 46 | } 47 | } 48 | 49 | #[derive(Debug)] 50 | struct RpnStack { 51 | stack: VecDeque, 52 | } 53 | 54 | impl RpnStack { 55 | fn new() -> RpnStack { 56 | RpnStack { 57 | stack: VecDeque::new(), 58 | } 59 | } 60 | 61 | fn push(&mut self, value: i32) { 62 | self.stack.push_front(value); 63 | } 64 | 65 | fn pop(&mut self) -> Result { 66 | match self.stack.pop_front() { 67 | Some(value) => Ok(value), 68 | None => Err(Error::PopFromEmptyStack), 69 | } 70 | } 71 | } 72 | 73 | fn evaluate(problem: &str) -> Result { 74 | let mut stack = RpnStack::new(); 75 | 76 | for term in problem.trim().split(' ') { 77 | match term { 78 | "+" => { 79 | let y = stack.pop()?; 80 | let x = stack.pop()?; 81 | stack.push(x + y); 82 | } 83 | "-" => { 84 | let y = stack.pop()?; 85 | let x = stack.pop()?; 86 | stack.push(x - y); 87 | } 88 | "*" => { 89 | let y = stack.pop()?; 90 | let x = stack.pop()?; 91 | stack.push(x * y); 92 | } 93 | "/" => { 94 | let y = stack.pop()?; 95 | let x = stack.pop()?; 96 | stack.push(x / y); 97 | } 98 | other => match other.parse() { 99 | Ok(value) => stack.push(value), 100 | Err(_) => return Err(Error::InvalidNumber), 101 | }, 102 | } 103 | } 104 | 105 | let value = stack.pop()?; 106 | Ok(value) 107 | } 108 | -------------------------------------------------------------------------------- /chapter-04/.gitignore: -------------------------------------------------------------------------------- 1 | */ngx-run/* 2 | !*/ngx-run/nginx.conf 3 | -------------------------------------------------------------------------------- /chapter-04/listing_01_module_starter/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-04-listing-01" 3 | version = "0.1.0" 4 | authors = ["Lily Mara "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /chapter-04/listing_01_module_starter/module/config: -------------------------------------------------------------------------------- 1 | ngx_module_type=HTTP 2 | ngx_module_name=ngx_http_calculator 3 | ngx_module_srcs="$ngx_addon_dir/ngx_http_calculator.c" 4 | ngx_module_libs="" 5 | 6 | . auto/module 7 | 8 | ngx_addon_name=$ngx_module_name 9 | -------------------------------------------------------------------------------- /chapter-04/listing_01_module_starter/module/ngx_http_calculator.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | typedef struct { 6 | ngx_flag_t enable_calculation; 7 | } ngx_http_calculator_loc_conf_t; 8 | 9 | ngx_int_t ngx_http_calculator_handler(ngx_http_request_t *r); 10 | 11 | static void *ngx_http_calculator_create_loc_conf(ngx_conf_t *cf); 12 | static char *ngx_http_calculator_merge_loc_conf(ngx_conf_t *cf, void *parent, 13 | void *child); 14 | 15 | static ngx_command_t ngx_http_calculator_commands[] = { 16 | {ngx_string("calculate"), NGX_HTTP_LOC_CONF | NGX_CONF_FLAG, 17 | ngx_conf_set_flag_slot, NGX_HTTP_LOC_CONF_OFFSET, 18 | offsetof(ngx_http_calculator_loc_conf_t, enable_calculation), NULL}, 19 | ngx_null_command}; 20 | 21 | static ngx_http_module_t ngx_http_calculator_module_ctx = { 22 | NULL, /* preconfiguration */ 23 | NULL, /* postconfiguration */ 24 | NULL, /* create main configuration */ 25 | NULL, /* init main configuration */ 26 | 27 | NULL, /* create server configuration */ 28 | NULL, /* merge server configuration */ 29 | 30 | ngx_http_calculator_create_loc_conf, /* create location configuration */ 31 | ngx_http_calculator_merge_loc_conf /* merge location configuration */ 32 | }; 33 | 34 | ngx_module_t ngx_http_calculator = { 35 | NGX_MODULE_V1, 36 | &ngx_http_calculator_module_ctx, /* module context */ 37 | ngx_http_calculator_commands, /* module directives */ 38 | NGX_HTTP_MODULE, /* module type */ 39 | NULL, /* init master */ 40 | NULL, /* init module */ 41 | NULL, /* init process */ 42 | NULL, /* init thread */ 43 | NULL, /* exit thread */ 44 | NULL, /* exit process */ 45 | NULL, /* exit master */ 46 | NGX_MODULE_V1_PADDING}; 47 | 48 | static void *ngx_http_calculator_create_loc_conf(ngx_conf_t *cf) { 49 | ngx_http_calculator_loc_conf_t *conf; 50 | 51 | conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_calculator_loc_conf_t)); 52 | if (conf == NULL) { 53 | return NULL; 54 | } 55 | 56 | conf->enable_calculation = NGX_CONF_UNSET; 57 | 58 | return conf; 59 | } 60 | 61 | static char *ngx_http_calculator_merge_loc_conf(ngx_conf_t *cf, void *parent, 62 | void *child) { 63 | ngx_http_calculator_loc_conf_t *prev = parent; 64 | ngx_http_calculator_loc_conf_t *conf = child; 65 | 66 | ngx_conf_merge_value(conf->enable_calculation, prev->enable_calculation, 0); 67 | 68 | if (conf->enable_calculation) { 69 | ngx_http_core_loc_conf_t *clcf; 70 | 71 | clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); 72 | clcf->handler = ngx_http_calculator_handler; 73 | } 74 | 75 | return NGX_CONF_OK; 76 | } 77 | -------------------------------------------------------------------------------- /chapter-04/listing_01_module_starter/ngx-run/nginx.conf: -------------------------------------------------------------------------------- 1 | load_module ../nginx-1.19.3/objs/ngx_http_calculator.so; 2 | 3 | daemon off; 4 | 5 | events { 6 | worker_connections 1024; 7 | } 8 | 9 | http { 10 | server { 11 | listen 8080; 12 | server_name localhost; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /chapter-04/listing_01_module_starter/run: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -xe 4 | 5 | rm -fr nginx-1.19.3.tar.gz nginx-1.19.3 6 | 7 | mkdir -p ngx-run/logs 8 | 9 | curl -L -o nginx-1.19.3.tar.gz https://nginx.org/download/nginx-1.19.3.tar.gz 10 | tar -xzf nginx-1.19.3.tar.gz 11 | 12 | pushd nginx-1.19.3 13 | 14 | ./configure --add-dynamic-module=../module 15 | 16 | make -j16 build modules 17 | 18 | popd 19 | 20 | ./nginx-1.19.3/objs/nginx -c nginx.conf -p ngx-run 21 | -------------------------------------------------------------------------------- /chapter-04/listing_01_module_starter/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | #[test] 4 | fn it_works() { 5 | assert_eq!(2 + 2, 4); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /chapter-04/listing_02_build_script_hello/.gitignore: -------------------------------------------------------------------------------- 1 | src/greet.rs 2 | -------------------------------------------------------------------------------- /chapter-04/listing_02_build_script_hello/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-04-listing-02" 3 | version = "0.1.0" 4 | authors = ["Lily Mara "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /chapter-04/listing_02_build_script_hello/build.rs: -------------------------------------------------------------------------------- 1 | use std::fs::File; 2 | use std::io::Write; // <1> 3 | 4 | fn main() { 5 | let language = std::env::var("GREET_LANG").unwrap(); // <2> 6 | 7 | let mut file = File::create("src/greet.rs").unwrap(); // <3> 8 | file.write_all(language.as_bytes()).unwrap(); // <4> 9 | } 10 | -------------------------------------------------------------------------------- /chapter-04/listing_02_build_script_hello/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | println!("Hello, world!"); 3 | } 4 | -------------------------------------------------------------------------------- /chapter-04/listing_03_build_script_language/.gitignore: -------------------------------------------------------------------------------- 1 | src/greet.rs 2 | -------------------------------------------------------------------------------- /chapter-04/listing_03_build_script_language/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-04-listing-03" 3 | version = "0.1.0" 4 | authors = ["Lily Mara "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /chapter-04/listing_03_build_script_language/build.rs: -------------------------------------------------------------------------------- 1 | use std::fs::File; 2 | use std::io::Write; 3 | 4 | fn main() { 5 | let language = std::env::var("GREET_LANG").unwrap(); 6 | 7 | let greeting = match language.as_ref() { 8 | "en" => "hello!", 9 | "es" => "¡hola!", 10 | "pa" => "ਸਤ ਸ੍ਰੀ ਅਕਾਲ", 11 | "zh" => "你好", 12 | x => panic!("Unsupported language code {}", x), 13 | }; 14 | 15 | let rust_code = format!("fn greet() {{ println!(\"{}\"); }}", greeting); 16 | 17 | let mut file = File::create("src/greet.rs").unwrap(); 18 | file.write_all(rust_code.as_bytes()).unwrap(); 19 | } 20 | -------------------------------------------------------------------------------- /chapter-04/listing_03_build_script_language/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | println!("Hello, world!"); 3 | } 4 | -------------------------------------------------------------------------------- /chapter-04/listing_04_build_script_include/.gitignore: -------------------------------------------------------------------------------- 1 | src/greet.rs 2 | -------------------------------------------------------------------------------- /chapter-04/listing_04_build_script_include/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-04-listing-04" 3 | version = "0.1.0" 4 | authors = ["Lily Mara "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /chapter-04/listing_04_build_script_include/build.rs: -------------------------------------------------------------------------------- 1 | use std::fs::File; 2 | use std::io::Write; 3 | 4 | fn main() { 5 | let language = std::env::var("GREET_LANG").unwrap(); 6 | 7 | let greeting = match language.as_ref() { 8 | "en" => "hello!", 9 | "es" => "¡hola!", 10 | "pa" => "ਸਤ ਸ੍ਰੀ ਅਕਾਲ", 11 | "zh" => "你好", 12 | x => panic!("Unsupported language code {}", x), 13 | }; 14 | 15 | let rust_code = format!("fn greet() {{ println!(\"{}\"); }}", greeting); 16 | 17 | let mut file = File::create("src/greet.rs").unwrap(); 18 | file.write_all(rust_code.as_bytes()).unwrap(); 19 | } 20 | -------------------------------------------------------------------------------- /chapter-04/listing_04_build_script_include/src/main.rs: -------------------------------------------------------------------------------- 1 | include!("greet.rs"); 2 | 3 | fn main() { 4 | greet(); 5 | } 6 | -------------------------------------------------------------------------------- /chapter-04/listing_05_build_script_bindings/.gitignore: -------------------------------------------------------------------------------- 1 | nginx.rs 2 | -------------------------------------------------------------------------------- /chapter-04/listing_05_build_script_bindings/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-04-listing-05" 3 | version = "0.1.0" 4 | authors = ["Lily Mara "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | 11 | [build-dependencies] 12 | bindgen = "0.56.0" 13 | -------------------------------------------------------------------------------- /chapter-04/listing_05_build_script_bindings/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let nginx_dir = "nginx-1.19.3"; 3 | 4 | let bindings = bindgen::builder() 5 | .header("wrapper.h") 6 | .clang_args(vec![ 7 | format!("-I{}/src/core", nginx_dir), 8 | format!("-I{}/src/event", nginx_dir), 9 | format!("-I{}/src/event/modules", nginx_dir), 10 | format!("-I{}/src/os/unix", nginx_dir), 11 | format!("-I{}/objs", nginx_dir), 12 | format!("-I{}/src/http", nginx_dir), 13 | format!("-I{}/src/http/v2", nginx_dir), 14 | format!("-I{}/src/http/modules", nginx_dir), 15 | ]) 16 | .generate() 17 | .expect("Unable to generate bindings"); 18 | 19 | bindings 20 | .write_to_file("nginx.rs") 21 | .expect("unable to write bindings"); 22 | } 23 | -------------------------------------------------------------------------------- /chapter-04/listing_05_build_script_bindings/module/config: -------------------------------------------------------------------------------- 1 | ngx_module_type=HTTP 2 | ngx_module_name=ngx_http_calculator 3 | ngx_module_srcs="$ngx_addon_dir/ngx_http_calculator.c" 4 | ngx_module_libs="" 5 | 6 | . auto/module 7 | 8 | ngx_addon_name=$ngx_module_name 9 | -------------------------------------------------------------------------------- /chapter-04/listing_05_build_script_bindings/ngx-run/nginx.conf: -------------------------------------------------------------------------------- 1 | load_module ../nginx-1.19.3/objs/ngx_http_calculator.so; 2 | 3 | worker_processes 1; 4 | daemon off; 5 | error_log /dev/stderr info; 6 | 7 | events { 8 | worker_connections 1024; 9 | } 10 | 11 | http { 12 | access_log /dev/stdout; 13 | 14 | server { 15 | listen 8080; 16 | 17 | location /calculate { 18 | calculate on; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /chapter-04/listing_05_build_script_bindings/run: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -xe 4 | 5 | rm -fr nginx-1.19.3.tar.gz nginx-1.19.3 6 | 7 | mkdir -p ngx-run/logs 8 | 9 | curl -L -o nginx-1.19.3.tar.gz https://nginx.org/download/nginx-1.19.3.tar.gz 10 | tar -xzf nginx-1.19.3.tar.gz 11 | 12 | pushd nginx-1.19.3 13 | 14 | ./configure --add-dynamic-module=../module 15 | 16 | make -j16 build modules 17 | 18 | popd 19 | 20 | ./nginx-1.19.3/objs/nginx -c nginx.conf -p ngx-run 21 | -------------------------------------------------------------------------------- /chapter-04/listing_05_build_script_bindings/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | #[test] 4 | fn it_works() { 5 | assert_eq!(2 + 2, 4); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /chapter-04/listing_05_build_script_bindings/wrapper.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | -------------------------------------------------------------------------------- /chapter-04/listing_06_build_script_ngx_prefix/.gitignore: -------------------------------------------------------------------------------- 1 | nginx.rs 2 | -------------------------------------------------------------------------------- /chapter-04/listing_06_build_script_ngx_prefix/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-04-listing-06" 3 | version = "0.1.0" 4 | authors = ["Lily Mara "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | 11 | [build-dependencies] 12 | bindgen = "0.56.0" 13 | -------------------------------------------------------------------------------- /chapter-04/listing_06_build_script_ngx_prefix/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let nginx_dir = "nginx-1.19.3"; 3 | 4 | let bindings = bindgen::builder() 5 | .header("wrapper.h") 6 | .whitelist_type("ngx_.*") 7 | .whitelist_function("ngx_.*") 8 | .whitelist_var("ngx_.*") 9 | .clang_args(vec![ 10 | format!("-I{}/src/core", nginx_dir), 11 | format!("-I{}/src/event", nginx_dir), 12 | format!("-I{}/src/event/modules", nginx_dir), 13 | format!("-I{}/src/os/unix", nginx_dir), 14 | format!("-I{}/objs", nginx_dir), 15 | format!("-I{}/src/http", nginx_dir), 16 | format!("-I{}/src/http/v2", nginx_dir), 17 | format!("-I{}/src/http/modules", nginx_dir), 18 | ]) 19 | .generate() 20 | .expect("Unable to generate bindings"); 21 | 22 | bindings 23 | .write_to_file("nginx.rs") 24 | .expect("unable to write bindings"); 25 | } 26 | -------------------------------------------------------------------------------- /chapter-04/listing_06_build_script_ngx_prefix/module/config: -------------------------------------------------------------------------------- 1 | ngx_module_type=HTTP 2 | ngx_module_name=ngx_http_calculator 3 | ngx_module_srcs="$ngx_addon_dir/ngx_http_calculator.c" 4 | ngx_module_libs="" 5 | 6 | . auto/module 7 | 8 | ngx_addon_name=$ngx_module_name 9 | -------------------------------------------------------------------------------- /chapter-04/listing_06_build_script_ngx_prefix/ngx-run/nginx.conf: -------------------------------------------------------------------------------- 1 | load_module ../nginx-1.19.3/objs/ngx_http_calculator.so; 2 | 3 | worker_processes 1; 4 | daemon off; 5 | error_log /dev/stderr info; 6 | 7 | events { 8 | worker_connections 1024; 9 | } 10 | 11 | http { 12 | access_log /dev/stdout; 13 | 14 | server { 15 | listen 8080; 16 | 17 | location /calculate { 18 | calculate on; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /chapter-04/listing_06_build_script_ngx_prefix/run: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -xe 4 | 5 | rm -fr nginx-1.19.3.tar.gz nginx-1.19.3 6 | 7 | mkdir -p ngx-run/logs 8 | 9 | curl -L -o nginx-1.19.3.tar.gz https://nginx.org/download/nginx-1.19.3.tar.gz 10 | tar -xzf nginx-1.19.3.tar.gz 11 | 12 | pushd nginx-1.19.3 13 | 14 | ./configure --add-dynamic-module=../module 15 | 16 | make -j16 build modules 17 | 18 | popd 19 | 20 | ./nginx-1.19.3/objs/nginx -c nginx.conf -p ngx-run 21 | -------------------------------------------------------------------------------- /chapter-04/listing_06_build_script_ngx_prefix/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | #[test] 4 | fn it_works() { 5 | assert_eq!(2 + 2, 4); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /chapter-04/listing_06_build_script_ngx_prefix/wrapper.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | -------------------------------------------------------------------------------- /chapter-04/listing_07_nginx_handler/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-04-listing-07" 3 | version = "0.1.0" 4 | authors = ["Lily Mara "] 5 | edition = "2018" 6 | 7 | [lib] 8 | crate-type = ["cdylib"] 9 | 10 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 11 | 12 | [dependencies] 13 | 14 | [build-dependencies] 15 | bindgen = "0.56.0" 16 | -------------------------------------------------------------------------------- /chapter-04/listing_07_nginx_handler/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let nginx_dir = "nginx-1.19.3"; 3 | 4 | let bindings = bindgen::builder() 5 | .header("wrapper.h") 6 | .whitelist_type("ngx_.*") 7 | .whitelist_function("ngx_.*") 8 | .whitelist_var("ngx_.*") 9 | .clang_args(vec![ 10 | format!("-I{}/src/core", nginx_dir), 11 | format!("-I{}/src/event", nginx_dir), 12 | format!("-I{}/src/event/modules", nginx_dir), 13 | format!("-I{}/src/os/unix", nginx_dir), 14 | format!("-I{}/objs", nginx_dir), 15 | format!("-I{}/src/http", nginx_dir), 16 | format!("-I{}/src/http/v2", nginx_dir), 17 | format!("-I{}/src/http/modules", nginx_dir), 18 | ]) 19 | .generate() 20 | .expect("Unable to generate bindings"); 21 | 22 | let out_dir = std::env::var("OUT_DIR").unwrap(); 23 | 24 | bindings 25 | .write_to_file(format!("{}/nginx.rs", out_dir)) 26 | .expect("unable to write bindings"); 27 | } 28 | -------------------------------------------------------------------------------- /chapter-04/listing_07_nginx_handler/module/config: -------------------------------------------------------------------------------- 1 | ngx_module_type=HTTP 2 | ngx_module_name=ngx_http_calculator 3 | ngx_module_srcs="$ngx_addon_dir/ngx_http_calculator.c" 4 | ngx_module_libs="/tmp/libngx_http_calculator_rs.so" 5 | 6 | . auto/module 7 | 8 | ngx_addon_name=$ngx_module_name 9 | -------------------------------------------------------------------------------- /chapter-04/listing_07_nginx_handler/module/ngx_http_calculator.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | typedef struct { 6 | ngx_flag_t enable_calculation; 7 | } ngx_http_calculator_loc_conf_t; 8 | 9 | ngx_int_t ngx_http_calculator_handler(ngx_http_request_t *r); 10 | 11 | static void *ngx_http_calculator_create_loc_conf(ngx_conf_t *cf); 12 | static char *ngx_http_calculator_merge_loc_conf(ngx_conf_t *cf, void *parent, 13 | void *child); 14 | 15 | static ngx_command_t ngx_http_calculator_commands[] = { 16 | {ngx_string("calculate"), NGX_HTTP_LOC_CONF | NGX_CONF_FLAG, 17 | ngx_conf_set_flag_slot, NGX_HTTP_LOC_CONF_OFFSET, 18 | offsetof(ngx_http_calculator_loc_conf_t, enable_calculation), NULL}, 19 | ngx_null_command}; 20 | 21 | static ngx_http_module_t ngx_http_calculator_module_ctx = { 22 | NULL, /* preconfiguration */ 23 | NULL, /* postconfiguration */ 24 | NULL, /* create main configuration */ 25 | NULL, /* init main configuration */ 26 | 27 | NULL, /* create server configuration */ 28 | NULL, /* merge server configuration */ 29 | 30 | ngx_http_calculator_create_loc_conf, /* create location configuration */ 31 | ngx_http_calculator_merge_loc_conf /* merge location configuration */ 32 | }; 33 | 34 | ngx_module_t ngx_http_calculator = { 35 | NGX_MODULE_V1, 36 | &ngx_http_calculator_module_ctx, /* module context */ 37 | ngx_http_calculator_commands, /* module directives */ 38 | NGX_HTTP_MODULE, /* module type */ 39 | NULL, /* init master */ 40 | NULL, /* init module */ 41 | NULL, /* init process */ 42 | NULL, /* init thread */ 43 | NULL, /* exit thread */ 44 | NULL, /* exit process */ 45 | NULL, /* exit master */ 46 | NGX_MODULE_V1_PADDING}; 47 | 48 | static void *ngx_http_calculator_create_loc_conf(ngx_conf_t *cf) { 49 | ngx_http_calculator_loc_conf_t *conf; 50 | 51 | conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_calculator_loc_conf_t)); 52 | if (conf == NULL) { 53 | return NULL; 54 | } 55 | 56 | conf->enable_calculation = NGX_CONF_UNSET; 57 | 58 | return conf; 59 | } 60 | 61 | static char *ngx_http_calculator_merge_loc_conf(ngx_conf_t *cf, void *parent, 62 | void *child) { 63 | ngx_http_calculator_loc_conf_t *prev = parent; 64 | ngx_http_calculator_loc_conf_t *conf = child; 65 | 66 | ngx_conf_merge_value(conf->enable_calculation, prev->enable_calculation, 0); 67 | 68 | if (conf->enable_calculation) { 69 | ngx_http_core_loc_conf_t *clcf; 70 | 71 | clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); 72 | clcf->handler = ngx_http_calculator_handler; 73 | } 74 | 75 | return NGX_CONF_OK; 76 | } 77 | -------------------------------------------------------------------------------- /chapter-04/listing_07_nginx_handler/ngx-run/nginx.conf: -------------------------------------------------------------------------------- 1 | load_module ../nginx-1.19.3/objs/ngx_http_calculator.so; 2 | 3 | worker_processes 1; 4 | daemon off; 5 | error_log /dev/stderr info; 6 | 7 | events { 8 | worker_connections 1024; 9 | } 10 | 11 | http { 12 | access_log /dev/stdout; 13 | 14 | server { 15 | listen 8080; 16 | 17 | location /calculate { 18 | calculate on; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /chapter-04/listing_07_nginx_handler/run: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -xe 4 | 5 | rm -fr nginx-1.19.3.tar.gz nginx-1.19.3 /tmp/libngx_http_calculator_rs.so 6 | 7 | mkdir -p ngx-run/logs 8 | 9 | curl -L -o nginx-1.19.3.tar.gz https://nginx.org/download/nginx-1.19.3.tar.gz 10 | tar -xzf nginx-1.19.3.tar.gz 11 | 12 | pushd nginx-1.19.3 13 | ./configure --add-dynamic-module=../module 14 | popd 15 | 16 | cargo build 17 | 18 | mv ../../target/debug/libchapter_04_listing_07.so /tmp/libngx_http_calculator_rs.so 19 | 20 | pushd nginx-1.19.3 21 | make -j16 build modules 22 | popd 23 | 24 | 25 | ./nginx-1.19.3/objs/nginx -c nginx.conf -p ngx-run 26 | -------------------------------------------------------------------------------- /chapter-04/listing_07_nginx_handler/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_upper_case_globals)] 2 | #![allow(non_camel_case_types)] 3 | #![allow(non_snake_case)] 4 | #![allow(dead_code)] 5 | include!(concat!(env!("OUT_DIR"), "/nginx.rs")); 6 | 7 | #[no_mangle] 8 | pub unsafe extern "C" fn ngx_http_calculator_handler( 9 | r: *mut ngx_http_request_t, 10 | ) -> ngx_int_t { 11 | eprintln!("Hello from Rust!"); 12 | 13 | 0 14 | } 15 | -------------------------------------------------------------------------------- /chapter-04/listing_07_nginx_handler/wrapper.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | -------------------------------------------------------------------------------- /chapter-04/listing_08_request_body/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-04-listing-08" 3 | version = "0.1.0" 4 | authors = ["Lily Mara "] 5 | edition = "2018" 6 | 7 | [lib] 8 | crate-type = ["cdylib"] 9 | 10 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 11 | 12 | [dependencies] 13 | 14 | [build-dependencies] 15 | bindgen = "0.56.0" 16 | -------------------------------------------------------------------------------- /chapter-04/listing_08_request_body/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let nginx_dir = "nginx-1.19.3"; 3 | 4 | let bindings = bindgen::builder() 5 | .header("wrapper.h") 6 | .whitelist_type("ngx_.*") 7 | .whitelist_function("ngx_.*") 8 | .whitelist_var("ngx_.*") 9 | .clang_args(vec![ 10 | format!("-I{}/src/core", nginx_dir), 11 | format!("-I{}/src/event", nginx_dir), 12 | format!("-I{}/src/event/modules", nginx_dir), 13 | format!("-I{}/src/os/unix", nginx_dir), 14 | format!("-I{}/objs", nginx_dir), 15 | format!("-I{}/src/http", nginx_dir), 16 | format!("-I{}/src/http/v2", nginx_dir), 17 | format!("-I{}/src/http/modules", nginx_dir), 18 | ]) 19 | .generate() 20 | .expect("Unable to generate bindings"); 21 | 22 | let out_dir = std::env::var("OUT_DIR").unwrap(); 23 | 24 | bindings 25 | .write_to_file(format!("{}/nginx.rs", out_dir)) 26 | .expect("unable to write bindings"); 27 | } 28 | -------------------------------------------------------------------------------- /chapter-04/listing_08_request_body/module/config: -------------------------------------------------------------------------------- 1 | ngx_module_type=HTTP 2 | ngx_module_name=ngx_http_calculator 3 | ngx_module_srcs="$ngx_addon_dir/ngx_http_calculator.c" 4 | ngx_module_libs="/tmp/libngx_http_calculator_rs.so" 5 | 6 | . auto/module 7 | 8 | ngx_addon_name=$ngx_module_name 9 | -------------------------------------------------------------------------------- /chapter-04/listing_08_request_body/module/ngx_http_calculator.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | typedef struct { 6 | ngx_flag_t enable_calculation; 7 | } ngx_http_calculator_loc_conf_t; 8 | 9 | ngx_int_t ngx_http_calculator_handler(ngx_http_request_t *r); 10 | 11 | static void *ngx_http_calculator_create_loc_conf(ngx_conf_t *cf); 12 | static char *ngx_http_calculator_merge_loc_conf(ngx_conf_t *cf, void *parent, 13 | void *child); 14 | 15 | static ngx_command_t ngx_http_calculator_commands[] = { 16 | {ngx_string("calculate"), NGX_HTTP_LOC_CONF | NGX_CONF_FLAG, 17 | ngx_conf_set_flag_slot, NGX_HTTP_LOC_CONF_OFFSET, 18 | offsetof(ngx_http_calculator_loc_conf_t, enable_calculation), NULL}, 19 | ngx_null_command}; 20 | 21 | static ngx_http_module_t ngx_http_calculator_module_ctx = { 22 | NULL, /* preconfiguration */ 23 | NULL, /* postconfiguration */ 24 | NULL, /* create main configuration */ 25 | NULL, /* init main configuration */ 26 | 27 | NULL, /* create server configuration */ 28 | NULL, /* merge server configuration */ 29 | 30 | ngx_http_calculator_create_loc_conf, /* create location configuration */ 31 | ngx_http_calculator_merge_loc_conf /* merge location configuration */ 32 | }; 33 | 34 | ngx_module_t ngx_http_calculator = { 35 | NGX_MODULE_V1, 36 | &ngx_http_calculator_module_ctx, /* module context */ 37 | ngx_http_calculator_commands, /* module directives */ 38 | NGX_HTTP_MODULE, /* module type */ 39 | NULL, /* init master */ 40 | NULL, /* init module */ 41 | NULL, /* init process */ 42 | NULL, /* init thread */ 43 | NULL, /* exit thread */ 44 | NULL, /* exit process */ 45 | NULL, /* exit master */ 46 | NGX_MODULE_V1_PADDING}; 47 | 48 | static void *ngx_http_calculator_create_loc_conf(ngx_conf_t *cf) { 49 | ngx_http_calculator_loc_conf_t *conf; 50 | 51 | conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_calculator_loc_conf_t)); 52 | if (conf == NULL) { 53 | return NULL; 54 | } 55 | 56 | conf->enable_calculation = NGX_CONF_UNSET; 57 | 58 | return conf; 59 | } 60 | 61 | static char *ngx_http_calculator_merge_loc_conf(ngx_conf_t *cf, void *parent, 62 | void *child) { 63 | ngx_http_calculator_loc_conf_t *prev = parent; 64 | ngx_http_calculator_loc_conf_t *conf = child; 65 | 66 | ngx_conf_merge_value(conf->enable_calculation, prev->enable_calculation, 0); 67 | 68 | if (conf->enable_calculation) { 69 | ngx_http_core_loc_conf_t *clcf; 70 | 71 | clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); 72 | clcf->handler = ngx_http_calculator_handler; 73 | } 74 | 75 | return NGX_CONF_OK; 76 | } 77 | -------------------------------------------------------------------------------- /chapter-04/listing_08_request_body/ngx-run/nginx.conf: -------------------------------------------------------------------------------- 1 | load_module ../nginx-1.19.3/objs/ngx_http_calculator.so; 2 | 3 | worker_processes 1; 4 | daemon off; 5 | error_log /dev/stderr info; 6 | 7 | events { 8 | worker_connections 1024; 9 | } 10 | 11 | http { 12 | access_log /dev/stdout; 13 | 14 | server { 15 | listen 8080; 16 | 17 | location /calculate { 18 | calculate on; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /chapter-04/listing_08_request_body/run: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -xe 4 | 5 | rm -fr nginx-1.19.3.tar.gz nginx-1.19.3 /tmp/libngx_http_calculator_rs.so 6 | 7 | mkdir -p ngx-run/logs 8 | 9 | curl -L -o nginx-1.19.3.tar.gz https://nginx.org/download/nginx-1.19.3.tar.gz 10 | tar -xzf nginx-1.19.3.tar.gz 11 | 12 | pushd nginx-1.19.3 13 | ./configure --add-dynamic-module=../module 14 | popd 15 | 16 | cargo build 17 | 18 | mv ../../target/debug/libchapter_04_listing_08.so /tmp/libngx_http_calculator_rs.so 19 | 20 | pushd nginx-1.19.3 21 | make -j16 build modules 22 | popd 23 | 24 | 25 | ./nginx-1.19.3/objs/nginx -c nginx.conf -p ngx-run 26 | -------------------------------------------------------------------------------- /chapter-04/listing_08_request_body/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_upper_case_globals)] 2 | #![allow(non_camel_case_types)] 3 | #![allow(non_snake_case)] 4 | #![allow(dead_code)] 5 | include!(concat!(env!("OUT_DIR"), "/nginx.rs")); 6 | 7 | #[no_mangle] 8 | pub unsafe extern "C" fn ngx_http_calculator_handler( 9 | r: *mut ngx_http_request_t, 10 | ) -> ngx_int_t { 11 | let rc = ngx_http_read_client_request_body(r, Some(read_body_handler)); 12 | if rc != 0 { 13 | return rc; 14 | } 15 | 16 | 0 17 | } 18 | 19 | unsafe extern "C" fn read_body_handler(r: *mut ngx_http_request_t) { 20 | if r.is_null() { 21 | eprintln!("got null request in body handler"); 22 | return; 23 | } 24 | 25 | let request = &*r; 26 | 27 | let body = match request_body_as_str(request) { 28 | Ok(body) => body, 29 | Err(e) => { 30 | eprintln!("failed to parse body: {}", e); 31 | return; 32 | } 33 | }; 34 | 35 | eprintln!("Read request body: {:?}", body); 36 | } 37 | 38 | unsafe fn request_body_as_str<'a>( 39 | request: &'a ngx_http_request_t, 40 | ) -> Result<&'a str, &'static str> { 41 | if request.request_body.is_null() 42 | || (*request.request_body).bufs.is_null() 43 | || (*(*request.request_body).bufs).buf.is_null() 44 | { 45 | return Err("Request body buffers were not initialized as expected"); 46 | } 47 | 48 | let buf = (*(*request.request_body).bufs).buf; 49 | 50 | let start = (*buf).pos; 51 | let len = (*buf).last.offset_from(start) as usize; 52 | 53 | let body_bytes = std::slice::from_raw_parts(start, len); 54 | 55 | let body_str = std::str::from_utf8(body_bytes) 56 | .map_err(|_| "Body contains invalid UTF-8")?; 57 | 58 | Ok(body_str) 59 | } 60 | -------------------------------------------------------------------------------- /chapter-04/listing_08_request_body/wrapper.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | -------------------------------------------------------------------------------- /chapter-04/listing_09_print_vec/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-04-listing-09" 3 | version = "0.1.0" 4 | authors = ["Lily Mara "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /chapter-04/listing_09_print_vec/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let numbers = vec![1, 2, 3, 4, 5]; 3 | 4 | let value = &numbers[0]; 5 | 6 | println!("value: {}", value); 7 | } 8 | -------------------------------------------------------------------------------- /chapter-04/listing_10_print_vec_fn/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-04-listing-10" 3 | version = "0.1.0" 4 | authors = ["Lily Mara "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /chapter-04/listing_10_print_vec_fn/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let numbers = vec![1, 2, 3, 4, 5]; 3 | 4 | let value = get_value(&numbers); 5 | 6 | println!("value: {}", value); 7 | } 8 | 9 | fn get_value(numbers: &Vec) -> &i32 { 10 | &numbers[0] 11 | } 12 | -------------------------------------------------------------------------------- /chapter-04/listing_11_print_vec_fn_dangling_NO_COMPILE/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-04-listing-11" 3 | version = "0.1.0" 4 | authors = ["Lily Mara "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /chapter-04/listing_11_print_vec_fn_dangling_NO_COMPILE/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let numbers = vec![1, 2, 3, 4, 5]; 3 | 4 | let value = get_value(&numbers); 5 | 6 | println!("value: {}", value); 7 | } 8 | 9 | fn get_value() -> &i32 { 10 | let x = 4; 11 | &x 12 | } 13 | -------------------------------------------------------------------------------- /chapter-04/listing_12_print_vec_fn_ref_NO_COMPILE/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-04-listing-12" 3 | version = "0.1.0" 4 | authors = ["Lily Mara "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /chapter-04/listing_12_print_vec_fn_ref_NO_COMPILE/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let numbers = vec![1, 2, 3, 4, 5]; 3 | 4 | let value = get_value(&numbers, "Getting the number"); 5 | 6 | println!("value: {}", value); 7 | } 8 | 9 | fn get_value(numbers: &Vec, s: &str) -> &i32 { 10 | println!("{}", s); 11 | &numbers[0] 12 | } 13 | -------------------------------------------------------------------------------- /chapter-04/listing_13_print_vec_fn_lifetimes/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-04-listing-13" 3 | version = "0.1.0" 4 | authors = ["Lily Mara "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /chapter-04/listing_13_print_vec_fn_lifetimes/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let numbers = vec![1, 2, 3, 4, 5]; 3 | 4 | let value = get_value(&numbers, "Getting the number"); 5 | 6 | println!("value: {}", value); 7 | } 8 | 9 | fn get_value<'a>(numbers: &'a Vec, s: &str) -> &'a i32 { 10 | println!("{}", s); 11 | &numbers[0] 12 | } 13 | -------------------------------------------------------------------------------- /chapter-04/listing_14_calculate/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-04-listing-14" 3 | version = "0.1.0" 4 | authors = ["Lily Mara "] 5 | edition = "2018" 6 | # See more keys and their definitions at 7 | # https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [lib] 10 | crate-type = ["rlib", "cdylib"] 11 | 12 | [dependencies] 13 | libc = "0.2.80" 14 | -------------------------------------------------------------------------------- /chapter-04/listing_14_calculate/src/lib.rs: -------------------------------------------------------------------------------- 1 | use libc::{c_char, c_int}; 2 | use std::collections::VecDeque; 3 | use std::ffi::CStr; 4 | use std::fmt::{Display, Formatter}; 5 | 6 | #[no_mangle] 7 | pub extern "C" fn solve(line: *const c_char, solution: *mut c_int) -> c_int { 8 | if line.is_null() || solution.is_null() { 9 | return 1; 10 | } 11 | 12 | let c_str = unsafe { CStr::from_ptr(line) }; 13 | let r_str = match c_str.to_str() { 14 | Ok(s) => s, 15 | Err(e) => { 16 | eprintln!("UTF-8 Error: {}", e); 17 | return 1; 18 | } 19 | }; 20 | 21 | match evaluate(r_str) { 22 | Ok(value) => { 23 | unsafe { 24 | *solution = value as c_int; 25 | } 26 | 0 27 | } 28 | Err(e) => { 29 | eprintln!("Error: {}", e); 30 | 1 31 | } 32 | } 33 | } 34 | 35 | pub enum Error { 36 | InvalidNumber, 37 | PopFromEmptyStack, 38 | } 39 | 40 | impl Display for Error { 41 | fn fmt(&self, f: &mut Formatter) -> std::fmt::Result { 42 | match self { 43 | Error::InvalidNumber => write!(f, "Not a valid number or operator"), 44 | Error::PopFromEmptyStack => write!(f, "Tried to operate on empty stack"), 45 | } 46 | } 47 | } 48 | 49 | #[derive(Debug)] 50 | struct RpnStack { 51 | stack: VecDeque, 52 | } 53 | 54 | impl RpnStack { 55 | fn new() -> RpnStack { 56 | RpnStack { 57 | stack: VecDeque::new(), 58 | } 59 | } 60 | 61 | fn push(&mut self, value: i32) { 62 | self.stack.push_front(value); 63 | } 64 | 65 | fn pop(&mut self) -> Result { 66 | match self.stack.pop_front() { 67 | Some(value) => Ok(value), 68 | None => Err(Error::PopFromEmptyStack), 69 | } 70 | } 71 | } 72 | 73 | pub fn evaluate(problem: &str) -> Result { 74 | let mut stack = RpnStack::new(); 75 | 76 | for term in problem.trim().split(' ') { 77 | match term { 78 | "+" => { 79 | let y = stack.pop()?; 80 | let x = stack.pop()?; 81 | stack.push(x + y); 82 | } 83 | "-" => { 84 | let y = stack.pop()?; 85 | let x = stack.pop()?; 86 | stack.push(x - y); 87 | } 88 | "*" => { 89 | let y = stack.pop()?; 90 | let x = stack.pop()?; 91 | stack.push(x * y); 92 | } 93 | "/" => { 94 | let y = stack.pop()?; 95 | let x = stack.pop()?; 96 | stack.push(x / y); 97 | } 98 | other => match other.parse() { 99 | Ok(value) => stack.push(value), 100 | Err(_) => return Err(Error::InvalidNumber), 101 | }, 102 | } 103 | } 104 | 105 | let value = stack.pop()?; 106 | Ok(value) 107 | } 108 | -------------------------------------------------------------------------------- /chapter-04/listing_15_evaluate_expression/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-04-listing-15" 3 | version = "0.1.0" 4 | authors = ["Lily Mara "] 5 | edition = "2018" 6 | 7 | [lib] 8 | crate-type = ["cdylib"] 9 | 10 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 11 | 12 | [dependencies] 13 | calculate = { path = "../listing_14_calculate", package = "chapter-04-listing-14" } 14 | 15 | [build-dependencies] 16 | bindgen = "0.56.0" 17 | -------------------------------------------------------------------------------- /chapter-04/listing_15_evaluate_expression/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let nginx_dir = "nginx-1.19.3"; 3 | 4 | let bindings = bindgen::builder() 5 | .header("wrapper.h") 6 | .whitelist_type("ngx_.*") 7 | .whitelist_function("ngx_.*") 8 | .whitelist_var("ngx_.*") 9 | .clang_args(vec![ 10 | format!("-I{}/src/core", nginx_dir), 11 | format!("-I{}/src/event", nginx_dir), 12 | format!("-I{}/src/event/modules", nginx_dir), 13 | format!("-I{}/src/os/unix", nginx_dir), 14 | format!("-I{}/objs", nginx_dir), 15 | format!("-I{}/src/http", nginx_dir), 16 | format!("-I{}/src/http/v2", nginx_dir), 17 | format!("-I{}/src/http/modules", nginx_dir), 18 | ]) 19 | .generate() 20 | .expect("Unable to generate bindings"); 21 | 22 | let out_dir = std::env::var("OUT_DIR").unwrap(); 23 | 24 | bindings 25 | .write_to_file(format!("{}/nginx.rs", out_dir)) 26 | .expect("unable to write bindings"); 27 | } 28 | -------------------------------------------------------------------------------- /chapter-04/listing_15_evaluate_expression/module/config: -------------------------------------------------------------------------------- 1 | ngx_module_type=HTTP 2 | ngx_module_name=ngx_http_calculator 3 | ngx_module_srcs="$ngx_addon_dir/ngx_http_calculator.c" 4 | ngx_module_libs="/tmp/libngx_http_calculator_rs.so" 5 | 6 | . auto/module 7 | 8 | ngx_addon_name=$ngx_module_name 9 | -------------------------------------------------------------------------------- /chapter-04/listing_15_evaluate_expression/ngx-run/nginx.conf: -------------------------------------------------------------------------------- 1 | load_module ../nginx-1.19.3/objs/ngx_http_calculator.so; 2 | 3 | worker_processes 1; 4 | daemon off; 5 | error_log /dev/stderr info; 6 | 7 | events { 8 | worker_connections 1024; 9 | } 10 | 11 | http { 12 | access_log /dev/stdout; 13 | 14 | server { 15 | listen 8080; 16 | 17 | location /calculate { 18 | calculate on; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /chapter-04/listing_15_evaluate_expression/run: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -xe 4 | 5 | rm -fr nginx-1.19.3.tar.gz nginx-1.19.3 /tmp/libngx_http_calculator_rs.so 6 | 7 | mkdir -p ngx-run/logs 8 | 9 | curl -L -o nginx-1.19.3.tar.gz https://nginx.org/download/nginx-1.19.3.tar.gz 10 | tar -xzf nginx-1.19.3.tar.gz 11 | 12 | pushd nginx-1.19.3 13 | ./configure --add-dynamic-module=../module 14 | popd 15 | 16 | cargo build 17 | 18 | mv ../../target/debug/libchapter_04_listing_15.so /tmp/libngx_http_calculator_rs.so 19 | 20 | pushd nginx-1.19.3 21 | make -j16 build modules 22 | popd 23 | 24 | 25 | ./nginx-1.19.3/objs/nginx -c nginx.conf -p ngx-run 26 | -------------------------------------------------------------------------------- /chapter-04/listing_15_evaluate_expression/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_upper_case_globals)] 2 | #![allow(non_camel_case_types)] 3 | #![allow(non_snake_case)] 4 | #![allow(dead_code)] 5 | include!(concat!(env!("OUT_DIR"), "/nginx.rs")); 6 | 7 | #[no_mangle] 8 | pub unsafe extern "C" fn ngx_http_calculator_handler( 9 | r: *mut ngx_http_request_t, 10 | ) -> ngx_int_t { 11 | let rc = ngx_http_read_client_request_body(r, Some(read_body_handler)); 12 | if rc != 0 { 13 | return rc; 14 | } 15 | 16 | 0 17 | } 18 | 19 | unsafe extern "C" fn read_body_handler(r: *mut ngx_http_request_t) { 20 | if r.is_null() { 21 | eprintln!("got null request in body handler"); 22 | return; 23 | } 24 | 25 | let request = &*r; 26 | 27 | let body = match request_body_as_str(request) { 28 | Ok(body) => body, 29 | Err(e) => { 30 | eprintln!("failed to parse body: {}", e); 31 | return; 32 | } 33 | }; 34 | 35 | match calculate::evaluate(body) { 36 | Ok(result) => eprintln!("{} = {}", body, result), 37 | Err(e) => eprintln!("{} => error: {}", body, e), 38 | } 39 | } 40 | 41 | unsafe fn request_body_as_str<'a>( 42 | request: &'a ngx_http_request_t, 43 | ) -> Result<&'a str, &'static str> { 44 | if request.request_body.is_null() 45 | || (*request.request_body).bufs.is_null() 46 | || (*(*request.request_body).bufs).buf.is_null() 47 | { 48 | return Err("Request body buffers were not initialized as expected"); 49 | } 50 | 51 | let buf = (*(*request.request_body).bufs).buf; 52 | 53 | let start = (*buf).pos; 54 | let len = (*buf).last.offset_from(start) as usize; 55 | 56 | let body_bytes = std::slice::from_raw_parts(start, len); 57 | 58 | let body_str = std::str::from_utf8(body_bytes) 59 | .map_err(|_| "Body contains invalid UTF-8")?; 60 | 61 | Ok(body_str) 62 | } 63 | -------------------------------------------------------------------------------- /chapter-04/listing_15_evaluate_expression/wrapper.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | -------------------------------------------------------------------------------- /chapter-04/listing_16_full_handler/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-04-listing-16" 3 | version = "0.1.0" 4 | authors = ["Lily Mara "] 5 | edition = "2018" 6 | 7 | [lib] 8 | crate-type = ["cdylib"] 9 | 10 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 11 | 12 | [dependencies] 13 | calculate = { path = "../listing_14_calculate", package = "chapter-04-listing-14" } 14 | 15 | [build-dependencies] 16 | bindgen = "0.56.0" 17 | -------------------------------------------------------------------------------- /chapter-04/listing_16_full_handler/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let nginx_dir = "nginx-1.19.3"; 3 | 4 | let bindings = bindgen::builder() 5 | .header("wrapper.h") 6 | .whitelist_type("ngx_.*") 7 | .whitelist_function("ngx_.*") 8 | .whitelist_var("ngx_.*") 9 | .clang_args(vec![ 10 | format!("-I{}/src/core", nginx_dir), 11 | format!("-I{}/src/event", nginx_dir), 12 | format!("-I{}/src/event/modules", nginx_dir), 13 | format!("-I{}/src/os/unix", nginx_dir), 14 | format!("-I{}/objs", nginx_dir), 15 | format!("-I{}/src/http", nginx_dir), 16 | format!("-I{}/src/http/v2", nginx_dir), 17 | format!("-I{}/src/http/modules", nginx_dir), 18 | ]) 19 | .generate() 20 | .expect("Unable to generate bindings"); 21 | 22 | let out_dir = std::env::var("OUT_DIR").unwrap(); 23 | 24 | bindings 25 | .write_to_file(format!("{}/nginx.rs", out_dir)) 26 | .expect("unable to write bindings"); 27 | } 28 | -------------------------------------------------------------------------------- /chapter-04/listing_16_full_handler/module/config: -------------------------------------------------------------------------------- 1 | ngx_module_type=HTTP 2 | ngx_module_name=ngx_http_calculator 3 | ngx_module_srcs="$ngx_addon_dir/ngx_http_calculator.c" 4 | ngx_module_libs="/tmp/libngx_http_calculator_rs.so" 5 | 6 | . auto/module 7 | 8 | ngx_addon_name=$ngx_module_name 9 | -------------------------------------------------------------------------------- /chapter-04/listing_16_full_handler/module/ngx_http_calculator.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | typedef struct { 6 | ngx_flag_t enable_calculation; 7 | } ngx_http_calculator_loc_conf_t; 8 | 9 | ngx_int_t ngx_http_calculator_handler(ngx_http_request_t *r); 10 | 11 | static void *ngx_http_calculator_create_loc_conf(ngx_conf_t *cf); 12 | static char *ngx_http_calculator_merge_loc_conf(ngx_conf_t *cf, void *parent, 13 | void *child); 14 | 15 | static ngx_command_t ngx_http_calculator_commands[] = { 16 | {ngx_string("calculate"), NGX_HTTP_LOC_CONF | NGX_CONF_FLAG, 17 | ngx_conf_set_flag_slot, NGX_HTTP_LOC_CONF_OFFSET, 18 | offsetof(ngx_http_calculator_loc_conf_t, enable_calculation), NULL}, 19 | ngx_null_command}; 20 | 21 | static ngx_http_module_t ngx_http_calculator_module_ctx = { 22 | NULL, /* preconfiguration */ 23 | NULL, /* postconfiguration */ 24 | NULL, /* create main configuration */ 25 | NULL, /* init main configuration */ 26 | 27 | NULL, /* create server configuration */ 28 | NULL, /* merge server configuration */ 29 | 30 | ngx_http_calculator_create_loc_conf, /* create location configuration */ 31 | ngx_http_calculator_merge_loc_conf /* merge location configuration */ 32 | }; 33 | 34 | ngx_module_t ngx_http_calculator = { 35 | NGX_MODULE_V1, 36 | &ngx_http_calculator_module_ctx, /* module context */ 37 | ngx_http_calculator_commands, /* module directives */ 38 | NGX_HTTP_MODULE, /* module type */ 39 | NULL, /* init master */ 40 | NULL, /* init module */ 41 | NULL, /* init process */ 42 | NULL, /* init thread */ 43 | NULL, /* exit thread */ 44 | NULL, /* exit process */ 45 | NULL, /* exit master */ 46 | NGX_MODULE_V1_PADDING}; 47 | 48 | static void *ngx_http_calculator_create_loc_conf(ngx_conf_t *cf) { 49 | ngx_http_calculator_loc_conf_t *conf; 50 | 51 | conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_calculator_loc_conf_t)); 52 | if (conf == NULL) { 53 | return NULL; 54 | } 55 | 56 | conf->enable_calculation = NGX_CONF_UNSET; 57 | 58 | return conf; 59 | } 60 | 61 | static char *ngx_http_calculator_merge_loc_conf(ngx_conf_t *cf, void *parent, 62 | void *child) { 63 | ngx_http_calculator_loc_conf_t *prev = parent; 64 | ngx_http_calculator_loc_conf_t *conf = child; 65 | 66 | ngx_conf_merge_value(conf->enable_calculation, prev->enable_calculation, 0); 67 | 68 | if (conf->enable_calculation) { 69 | ngx_http_core_loc_conf_t *clcf; 70 | 71 | clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); 72 | clcf->handler = ngx_http_calculator_handler; 73 | } 74 | 75 | return NGX_CONF_OK; 76 | } 77 | -------------------------------------------------------------------------------- /chapter-04/listing_16_full_handler/ngx-run/nginx.conf: -------------------------------------------------------------------------------- 1 | load_module ../nginx-1.19.3/objs/ngx_http_calculator.so; 2 | 3 | worker_processes 1; 4 | daemon off; 5 | error_log /dev/stderr info; 6 | 7 | events { 8 | worker_connections 1024; 9 | } 10 | 11 | http { 12 | access_log /dev/stdout; 13 | 14 | server { 15 | listen 8080; 16 | 17 | location /calculate { 18 | calculate on; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /chapter-04/listing_16_full_handler/run: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -xe 4 | 5 | rm -fr nginx-1.19.3.tar.gz nginx-1.19.3 /tmp/libngx_http_calculator_rs.so 6 | 7 | mkdir -p ngx-run/logs 8 | 9 | curl -L -o nginx-1.19.3.tar.gz https://nginx.org/download/nginx-1.19.3.tar.gz 10 | tar -xzf nginx-1.19.3.tar.gz 11 | 12 | pushd nginx-1.19.3 13 | ./configure --add-dynamic-module=../module 14 | popd 15 | 16 | cargo build 17 | 18 | mv ../../target/debug/libchapter_04_listing_16.so /tmp/libngx_http_calculator_rs.so 19 | 20 | pushd nginx-1.19.3 21 | make -j16 build modules 22 | popd 23 | 24 | 25 | ./nginx-1.19.3/objs/nginx -c nginx.conf -p ngx-run 26 | -------------------------------------------------------------------------------- /chapter-04/listing_16_full_handler/wrapper.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | -------------------------------------------------------------------------------- /chapter-05/listing_01_greeter_start/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-05-listing-01" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /chapter-05/listing_01_greeter_start/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::io::stdin; 2 | 3 | fn main() { 4 | let name = get_name(); 5 | 6 | hello(&name); 7 | goodbye(&name); 8 | } 9 | 10 | fn get_name() -> String { 11 | let mut name = String::new(); 12 | 13 | println!("Please enter your name"); 14 | stdin().read_line(&mut name).unwrap(); 15 | 16 | name 17 | } 18 | 19 | fn goodbye(name: &str) { 20 | println!("Goodbye, {}", name); 21 | } 22 | 23 | fn hello(name: &str) { 24 | println!("Hello, {}", name); 25 | } 26 | -------------------------------------------------------------------------------- /chapter-05/listing_02_greeter_mod_NO_COMPILE/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-05-listing-02" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /chapter-05/listing_02_greeter_mod_NO_COMPILE/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let name = get_name(); 3 | 4 | hello(&name); 5 | goodbye(&name); 6 | } 7 | 8 | mod input { 9 | use std::io::stdin; 10 | 11 | fn get_name() -> String { 12 | let mut name = String::new(); 13 | 14 | println!("Please enter your name"); 15 | stdin().read_line(&mut name).unwrap(); 16 | 17 | name 18 | } 19 | } 20 | 21 | mod output { 22 | fn goodbye(name: &str) { 23 | println!("Goodbye, {}", name); 24 | } 25 | 26 | fn hello(name: &str) { 27 | println!("Hello, {}", name); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /chapter-05/listing_03_greeter_use_NO_COMPILE/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-05-listing-03" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /chapter-05/listing_03_greeter_use_NO_COMPILE/src/main.rs: -------------------------------------------------------------------------------- 1 | use input::get_name; 2 | use output::{goodbye, hello}; 3 | 4 | fn main() { 5 | let name = get_name(); 6 | 7 | hello(&name); 8 | goodbye(&name); 9 | } 10 | 11 | mod input { 12 | use std::io::stdin; 13 | 14 | fn get_name() -> String { 15 | let mut name = String::new(); 16 | 17 | println!("Please enter your name"); 18 | stdin().read_line(&mut name).unwrap(); 19 | 20 | name 21 | } 22 | } 23 | 24 | mod output { 25 | fn goodbye(name: &str) { 26 | println!("Goodbye, {}", name); 27 | } 28 | 29 | fn hello(name: &str) { 30 | println!("Hello, {}", name); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /chapter-05/listing_04_greeter_pub/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-05-listing-04" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /chapter-05/listing_04_greeter_pub/src/main.rs: -------------------------------------------------------------------------------- 1 | use input::get_name; 2 | use output::{goodbye, hello}; 3 | 4 | fn main() { 5 | let name = get_name(); 6 | 7 | hello(&name); 8 | goodbye(&name); 9 | } 10 | 11 | mod input { 12 | use std::io::stdin; 13 | 14 | pub fn get_name() -> String { 15 | let mut name = String::new(); 16 | 17 | println!("Please enter your name"); 18 | stdin().read_line(&mut name).unwrap(); 19 | 20 | name 21 | } 22 | } 23 | 24 | mod output { 25 | pub fn goodbye(name: &str) { 26 | println!("Goodbye, {}", name); 27 | } 28 | 29 | pub fn hello(name: &str) { 30 | println!("Hello, {}", name); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /chapter-05/listing_05_greeter_mod_files/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-05-listing-05" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /chapter-05/listing_05_greeter_mod_files/src/input.rs: -------------------------------------------------------------------------------- 1 | use std::io::stdin; 2 | 3 | pub fn get_name() -> String { 4 | let mut name = String::new(); 5 | 6 | println!("Please enter your name"); 7 | stdin().read_line(&mut name).unwrap(); 8 | 9 | name 10 | } 11 | -------------------------------------------------------------------------------- /chapter-05/listing_05_greeter_mod_files/src/main.rs: -------------------------------------------------------------------------------- 1 | use input::get_name; 2 | use output::{goodbye, hello}; 3 | 4 | mod input; 5 | mod output; 6 | 7 | fn main() { 8 | let name = get_name(); 9 | 10 | hello(&name); 11 | goodbye(&name); 12 | } 13 | -------------------------------------------------------------------------------- /chapter-05/listing_05_greeter_mod_files/src/output.rs: -------------------------------------------------------------------------------- 1 | pub fn goodbye(name: &str) { 2 | println!("Goodbye, {}", name); 3 | } 4 | 5 | pub fn hello(name: &str) { 6 | println!("Hello, {}", name); 7 | } 8 | -------------------------------------------------------------------------------- /chapter-05/listing_08_day_kind_NO_COMPILE/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-05-listing-08" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /chapter-05/listing_08_day_kind_NO_COMPILE/src/day_kind.rs: -------------------------------------------------------------------------------- 1 | pub enum DayKind { 2 | Good, 3 | Bad, 4 | } 5 | -------------------------------------------------------------------------------- /chapter-05/listing_08_day_kind_NO_COMPILE/src/input.rs: -------------------------------------------------------------------------------- 1 | use std::io::stdin; 2 | 3 | pub fn get_name() -> String { 4 | let mut name = String::new(); 5 | 6 | println!("Please enter your name"); 7 | stdin().read_line(&mut name).unwrap(); 8 | 9 | name 10 | } 11 | -------------------------------------------------------------------------------- /chapter-05/listing_08_day_kind_NO_COMPILE/src/main.rs: -------------------------------------------------------------------------------- 1 | use input::get_name; 2 | use output::{goodbye, hello}; 3 | 4 | mod day_kind; 5 | mod input; 6 | mod output; 7 | 8 | fn main() { 9 | let name = get_name(); 10 | 11 | hello(&name); 12 | goodbye(&name); 13 | } 14 | -------------------------------------------------------------------------------- /chapter-05/listing_08_day_kind_NO_COMPILE/src/output.rs: -------------------------------------------------------------------------------- 1 | use day_kind::DayKind; 2 | 3 | pub fn print_day_kind_message(day_kind: DayKind) { 4 | match day_kind { 5 | DayKind::Good => println!("I'm glad to hear you're having a good day!"), 6 | DayKind::Bad => println!("I'm sorry to hear you're having a bad day"), 7 | } 8 | } 9 | 10 | pub fn goodbye(name: &str) { 11 | println!("Goodbye, {}", name); 12 | } 13 | 14 | pub fn hello(name: &str) { 15 | println!("Hello, {}", name); 16 | } 17 | -------------------------------------------------------------------------------- /chapter-05/listing_11_paths/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-05-listing-11" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | [dependencies] 8 | -------------------------------------------------------------------------------- /chapter-05/listing_11_paths/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let value = true; 3 | 4 | // All of the lines below this are paths 5 | value; // <1> 6 | 7 | hello; // <2> 8 | 9 | std::io::stdin; // <3> 10 | 11 | std::collections::hash_map::ValuesMut::::len; // <4> 12 | } 13 | 14 | fn hello() {} 15 | -------------------------------------------------------------------------------- /chapter-05/listing_12_libsnack/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-05-listing-12" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /chapter-05/listing_12_libsnack/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod treats { 2 | pub mod shop {} 3 | 4 | pub enum Treat { 5 | Candy, 6 | IceCream, 7 | } 8 | 9 | pub struct ConsumedTreat { 10 | treat: Treat, 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /chapter-05/listing_13_libsnack_lifecycle_absolute/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-05-listing-13" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /chapter-05/listing_13_libsnack_lifecycle_absolute/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod treats { 2 | pub mod shop { 3 | fn buy() -> crate::treats::Treat { 4 | crate::treats::Treat::IceCream 5 | } 6 | } 7 | 8 | pub enum Treat { 9 | Candy, 10 | IceCream, 11 | } 12 | 13 | pub struct ConsumedTreat { 14 | treat: Treat, 15 | } 16 | 17 | fn eat(treat: crate::treats::Treat) -> crate::treats::ConsumedTreat { 18 | crate::treats::ConsumedTreat { treat } 19 | } 20 | } 21 | 22 | fn regret(treat: crate::treats::ConsumedTreat) { 23 | println!("That was a mistake"); 24 | } 25 | -------------------------------------------------------------------------------- /chapter-05/listing_14_libsnack_lifecycle_relative/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-05-listing-14" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /chapter-05/listing_14_libsnack_lifecycle_relative/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod treats { 2 | pub mod shop { 3 | fn buy() -> super::Treat { 4 | super::Treat::IceCream 5 | } 6 | } 7 | 8 | pub enum Treat { 9 | Candy, 10 | IceCream, 11 | } 12 | 13 | pub struct ConsumedTreat { 14 | treat: Treat, 15 | } 16 | 17 | fn eat(treat: Treat) -> ConsumedTreat { 18 | ConsumedTreat { treat } 19 | } 20 | } 21 | 22 | fn regret(treat: treats::ConsumedTreat) { 23 | println!("That was a mistake"); 24 | } 25 | -------------------------------------------------------------------------------- /chapter-05/listing_15_libsnack_lifecycle_use/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-05-listing-15" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /chapter-05/listing_15_libsnack_lifecycle_use/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod treats { 2 | pub mod shop { 3 | use crate::treats::Treat; 4 | 5 | fn buy() -> Treat { 6 | Treat::IceCream 7 | } 8 | } 9 | 10 | pub enum Treat { 11 | Candy, 12 | IceCream, 13 | } 14 | 15 | pub struct ConsumedTreat { 16 | treat: Treat, 17 | } 18 | 19 | fn eat(treat: Treat) -> ConsumedTreat { 20 | ConsumedTreat { treat } 21 | } 22 | } 23 | 24 | use treats::ConsumedTreat; 25 | 26 | fn regret(treat: ConsumedTreat) { 27 | println!("That was a mistake"); 28 | } 29 | -------------------------------------------------------------------------------- /chapter-05/listing_20_greeter_day_kind_input/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-05-listing-20" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /chapter-05/listing_20_greeter_day_kind_input/src/day_kind.rs: -------------------------------------------------------------------------------- 1 | pub enum DayKind { 2 | Good, 3 | Bad, 4 | } 5 | -------------------------------------------------------------------------------- /chapter-05/listing_20_greeter_day_kind_input/src/input.rs: -------------------------------------------------------------------------------- 1 | use crate::day_kind::DayKind; 2 | use std::io::stdin; 3 | 4 | pub fn get_name() -> String { 5 | let mut name = String::new(); 6 | 7 | println!("Please enter your name"); 8 | stdin().read_line(&mut name).unwrap(); 9 | 10 | name 11 | } 12 | 13 | pub fn how_was_day() -> DayKind { 14 | let mut day = String::new(); 15 | 16 | println!("How was your day?"); 17 | stdin().read_line(&mut day).unwrap(); 18 | 19 | let day_trimmed = day.trim(); 20 | 21 | if day_trimmed == "good" { 22 | DayKind::Good 23 | } else { 24 | DayKind::Bad 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /chapter-05/listing_20_greeter_day_kind_input/src/main.rs: -------------------------------------------------------------------------------- 1 | use input::get_name; 2 | use output::{goodbye, hello}; 3 | 4 | mod day_kind; 5 | mod input; 6 | mod output; 7 | 8 | fn main() { 9 | let name = get_name(); 10 | 11 | hello(&name); 12 | goodbye(&name); 13 | } 14 | -------------------------------------------------------------------------------- /chapter-05/listing_20_greeter_day_kind_input/src/output.rs: -------------------------------------------------------------------------------- 1 | use crate::day_kind::DayKind; 2 | 3 | pub fn print_day_kind_message(day_kind: DayKind) { 4 | match day_kind { 5 | DayKind::Good => println!("I'm glad to hear you're having a good day!"), 6 | DayKind::Bad => println!("I'm sorry to hear you're having a bad day"), 7 | } 8 | } 9 | 10 | pub fn goodbye(name: &str) { 11 | println!("Goodbye, {}", name); 12 | } 13 | 14 | pub fn hello(name: &str) { 15 | println!("Hello, {}", name); 16 | } 17 | -------------------------------------------------------------------------------- /chapter-05/listing_21_greeter_day_kind_main/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-05-listing-21" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /chapter-05/listing_21_greeter_day_kind_main/src/day_kind.rs: -------------------------------------------------------------------------------- 1 | pub enum DayKind { 2 | Good, 3 | Bad, 4 | } 5 | -------------------------------------------------------------------------------- /chapter-05/listing_21_greeter_day_kind_main/src/input.rs: -------------------------------------------------------------------------------- 1 | use crate::day_kind::DayKind; 2 | use std::io::stdin; 3 | 4 | pub fn get_name() -> String { 5 | let mut name = String::new(); 6 | 7 | println!("Please enter your name"); 8 | stdin().read_line(&mut name).unwrap(); 9 | 10 | name 11 | } 12 | 13 | pub fn how_was_day() -> DayKind { 14 | let mut day = String::new(); 15 | 16 | println!("How was your day?"); 17 | stdin().read_line(&mut day).unwrap(); 18 | 19 | let day_trimmed = day.trim(); 20 | 21 | if day_trimmed == "good" { 22 | DayKind::Good 23 | } else { 24 | DayKind::Bad 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /chapter-05/listing_21_greeter_day_kind_main/src/main.rs: -------------------------------------------------------------------------------- 1 | use input::{get_name, how_was_day}; 2 | use output::{goodbye, hello, print_day_kind_message}; 3 | 4 | mod day_kind; 5 | mod input; 6 | mod output; 7 | 8 | fn main() { 9 | let name = get_name(); 10 | 11 | hello(&name); 12 | 13 | let day_kind = how_was_day(); 14 | print_day_kind_message(day_kind); 15 | 16 | goodbye(&name); 17 | } 18 | -------------------------------------------------------------------------------- /chapter-05/listing_21_greeter_day_kind_main/src/output.rs: -------------------------------------------------------------------------------- 1 | use crate::day_kind::DayKind; 2 | 3 | pub fn print_day_kind_message(day_kind: DayKind) { 4 | match day_kind { 5 | DayKind::Good => println!("I'm glad to hear you're having a good day!"), 6 | DayKind::Bad => println!("I'm sorry to hear you're having a bad day"), 7 | } 8 | } 9 | 10 | pub fn goodbye(name: &str) { 11 | println!("Goodbye, {}", name); 12 | } 13 | 14 | pub fn hello(name: &str) { 15 | println!("Hello, {}", name); 16 | } 17 | -------------------------------------------------------------------------------- /chapter-05/listing_22_greeter_day_kind_read_line/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-05-listing-22" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /chapter-05/listing_22_greeter_day_kind_read_line/src/day_kind.rs: -------------------------------------------------------------------------------- 1 | pub enum DayKind { 2 | Good, 3 | Bad, 4 | } 5 | -------------------------------------------------------------------------------- /chapter-05/listing_22_greeter_day_kind_read_line/src/input.rs: -------------------------------------------------------------------------------- 1 | use crate::day_kind::DayKind; 2 | use std::io::stdin; 3 | 4 | fn read_line() -> String { 5 | let mut line = String::new(); 6 | 7 | stdin().read_line(&mut line).unwrap(); 8 | 9 | line.trim().to_string() 10 | } 11 | 12 | pub fn get_name() -> String { 13 | println!("Please enter your name"); 14 | read_line() 15 | } 16 | 17 | pub fn how_was_day() -> DayKind { 18 | println!("How was your day?"); 19 | let day = read_line(); 20 | 21 | if day == "good" { 22 | DayKind::Good 23 | } else { 24 | DayKind::Bad 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /chapter-05/listing_22_greeter_day_kind_read_line/src/main.rs: -------------------------------------------------------------------------------- 1 | use input::{get_name, how_was_day}; 2 | use output::{goodbye, hello, print_day_kind_message}; 3 | 4 | mod day_kind; 5 | mod input; 6 | mod output; 7 | 8 | fn main() { 9 | let name = get_name(); 10 | 11 | hello(&name); 12 | 13 | let day_kind = how_was_day(); 14 | print_day_kind_message(day_kind); 15 | 16 | goodbye(&name); 17 | } 18 | -------------------------------------------------------------------------------- /chapter-05/listing_22_greeter_day_kind_read_line/src/output.rs: -------------------------------------------------------------------------------- 1 | use crate::day_kind::DayKind; 2 | 3 | pub fn print_day_kind_message(day_kind: DayKind) { 4 | match day_kind { 5 | DayKind::Good => println!("I'm glad to hear you're having a good day!"), 6 | DayKind::Bad => println!("I'm sorry to hear you're having a bad day"), 7 | } 8 | } 9 | 10 | pub fn goodbye(name: &str) { 11 | println!("Goodbye, {}", name); 12 | } 13 | 14 | pub fn hello(name: &str) { 15 | println!("Hello, {}", name); 16 | } 17 | -------------------------------------------------------------------------------- /chapter-05/listing_23_greeter_pub_use/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-05-listing-23" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /chapter-05/listing_23_greeter_pub_use/src/day_kind.rs: -------------------------------------------------------------------------------- 1 | pub enum DayKind { 2 | Good, 3 | Bad, 4 | } 5 | -------------------------------------------------------------------------------- /chapter-05/listing_23_greeter_pub_use/src/input.rs: -------------------------------------------------------------------------------- 1 | use crate::DayKind; 2 | use std::io::stdin; 3 | 4 | fn read_line() -> String { 5 | let mut line = String::new(); 6 | 7 | stdin().read_line(&mut line).unwrap(); 8 | 9 | line.trim().to_string() 10 | } 11 | 12 | pub fn get_name() -> String { 13 | println!("Please enter your name"); 14 | read_line() 15 | } 16 | 17 | pub fn how_was_day() -> DayKind { 18 | println!("How was your day?"); 19 | let day = read_line(); 20 | 21 | if day == "good" { 22 | DayKind::Good 23 | } else { 24 | DayKind::Bad 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /chapter-05/listing_23_greeter_pub_use/src/main.rs: -------------------------------------------------------------------------------- 1 | use input::{get_name, how_was_day}; 2 | use output::{goodbye, hello, print_day_kind_message}; 3 | 4 | pub use day_kind::DayKind; 5 | 6 | mod day_kind; 7 | mod input; 8 | mod output; 9 | 10 | fn main() { 11 | let name = get_name(); 12 | 13 | hello(&name); 14 | 15 | let day_kind = how_was_day(); 16 | print_day_kind_message(day_kind); 17 | 18 | goodbye(&name); 19 | } 20 | -------------------------------------------------------------------------------- /chapter-05/listing_23_greeter_pub_use/src/output.rs: -------------------------------------------------------------------------------- 1 | use crate::DayKind; 2 | 3 | pub fn print_day_kind_message(day_kind: DayKind) { 4 | match day_kind { 5 | DayKind::Good => println!("I'm glad to hear you're having a good day!"), 6 | DayKind::Bad => println!("I'm sorry to hear you're having a bad day"), 7 | } 8 | } 9 | 10 | pub fn goodbye(name: &str) { 11 | println!("Goodbye, {}", name); 12 | } 13 | 14 | pub fn hello(name: &str) { 15 | println!("Hello, {}", name); 16 | } 17 | -------------------------------------------------------------------------------- /chapter-05/listing_27_forest/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-05-listing-27" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /chapter-05/listing_27_forest/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod forest { 2 | pub fn enter_area(area: &str) { 3 | match area { 4 | "tree cover" => println!("It's getting darker..."), 5 | "witches coven" => println!("It's getting spookier..."), 6 | "walking path" => println!("It's getting easier to walk..."), 7 | x => panic!("Unexpected area: {}", x), 8 | } 9 | } 10 | } 11 | 12 | pub mod tree_cover { 13 | pub fn enter() { 14 | crate::forest::enter_area("tree cover"); 15 | } 16 | } 17 | 18 | pub mod walking_path { 19 | pub fn enter() { 20 | crate::forest::enter_area("walking path"); 21 | } 22 | } 23 | 24 | pub mod witches_coven { 25 | pub fn enter() { 26 | crate::forest::enter_area("witches coven"); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /chapter-05/listing_28_forest_pvt_NO_COMPILE/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-05-listing-28" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /chapter-05/listing_28_forest_pvt_NO_COMPILE/src/lib.rs: -------------------------------------------------------------------------------- 1 | mod forest { 2 | fn enter_area(area: &str) { 3 | match area { 4 | "tree cover" => println!("It's getting darker..."), 5 | "witches coven" => println!("It's getting spookier..."), 6 | "walking path" => println!("It's getting easier to walk..."), 7 | x => panic!("Unexpected area: {}", x), 8 | } 9 | } 10 | } 11 | 12 | pub mod tree_cover { 13 | pub fn enter() { 14 | crate::forest::enter_area("tree cover"); 15 | } 16 | } 17 | 18 | pub mod walking_path { 19 | pub fn enter() { 20 | crate::forest::enter_area("walking path"); 21 | } 22 | } 23 | 24 | pub mod witches_coven { 25 | pub fn enter() { 26 | crate::forest::enter_area("witches coven"); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /chapter-05/listing_29_forest_pub_crate/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-05-listing-29" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /chapter-05/listing_29_forest_pub_crate/src/lib.rs: -------------------------------------------------------------------------------- 1 | mod forest { 2 | pub(crate) fn enter_area(area: &str) { 3 | match area { 4 | "tree cover" => println!("It's getting darker..."), 5 | "witches coven" => println!("It's getting spookier..."), 6 | "walking path" => println!("It's getting easier to walk..."), 7 | x => panic!("Unexpected area: {}", x), 8 | } 9 | } 10 | } 11 | 12 | pub mod tree_cover { 13 | pub fn enter() { 14 | crate::forest::enter_area("tree cover"); 15 | } 16 | } 17 | 18 | pub mod walking_path { 19 | pub fn enter() { 20 | crate::forest::enter_area("walking path"); 21 | } 22 | } 23 | 24 | pub mod witches_coven { 25 | pub fn enter() { 26 | crate::forest::enter_area("witches coven"); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /chapter-05/listing_30_nested_parent_visibility/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-05-listing-30" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /chapter-05/listing_30_nested_parent_visibility/src/lib.rs: -------------------------------------------------------------------------------- 1 | fn function() {} 2 | 3 | mod nested { 4 | fn function() { 5 | crate::function(); 6 | } 7 | 8 | mod very_nested { 9 | fn function() { 10 | crate::function(); 11 | crate::nested::function(); 12 | } 13 | 14 | mod very_very_nested { 15 | fn function() { 16 | crate::function(); 17 | crate::nested::function(); 18 | crate::nested::very_nested::function(); 19 | } 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /chapter-05/listing_31_nested_downward_visibility_doesnt_work_NO_COMPILE/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-05-listing-31" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /chapter-05/listing_31_nested_downward_visibility_doesnt_work_NO_COMPILE/src/lib.rs: -------------------------------------------------------------------------------- 1 | fn function() { 2 | nested::function(); 3 | } 4 | 5 | mod nested { 6 | fn function() { 7 | very_nested::function(); 8 | } 9 | 10 | mod very_nested { 11 | fn function() { 12 | very_very_nested::function(); 13 | } 14 | 15 | mod very_very_nested { 16 | fn function() {} 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /chapter-06/listing_00_complete/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-06-listing-00" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | [lib] 7 | name = "json_summer" 8 | crate-type = ["cdylib"] 9 | 10 | [dependencies] 11 | pyo3 = { version = "0.14", features = ["extension-module"] } 12 | serde = { version = "1.0.130", features = ["derive"] } 13 | serde_json = "1.0.68" 14 | -------------------------------------------------------------------------------- /chapter-06/listing_00_complete/src/lib.rs: -------------------------------------------------------------------------------- 1 | use pyo3::{exceptions::PyValueError, prelude::*}; 2 | use serde::Deserialize; 3 | 4 | #[derive(Deserialize)] 5 | struct Data { 6 | name: String, 7 | value: u16, 8 | } 9 | 10 | #[pyfunction] 11 | fn sum_json(input: &str) -> PyResult { 12 | let d: Data = serde_json::from_str(input) 13 | .map_err(|e| PyValueError::new_err(format!("{}", e)))?; 14 | 15 | Ok(d.value as u64 + d.name.len() as u64) 16 | } 17 | 18 | #[pymodule] 19 | fn json_summer(_py: Python, m: &PyModule) -> PyResult<()> { 20 | m.add_function(wrap_pyfunction!(sum_json, m)?)?; 21 | 22 | Ok(()) 23 | } 24 | -------------------------------------------------------------------------------- /chapter-06/listing_01_benching/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-06-listing-01" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | [[bench]] 7 | name = "py-vs-rust" 8 | harness = false 9 | 10 | [dev-dependencies] 11 | criterion = "0.3" 12 | pyo3 = "0.14" 13 | rand = "0.8" 14 | -------------------------------------------------------------------------------- /chapter-06/listing_01_benching/benches/py-vs-rust.rs: -------------------------------------------------------------------------------- 1 | use pyo3::prelude::*; 2 | use pyo3::types::PyDict; 3 | use rand::{distributions::Alphanumeric, thread_rng, Rng}; 4 | 5 | use criterion::{ 6 | black_box, criterion_group, criterion_main, Bencher, Criterion, 7 | Throughput, 8 | }; 9 | use std::{fmt::Write as _, iter, time::Duration}; 10 | 11 | fn bench_py(input: &str, imports: &[&str], code: &str, b: &mut Bencher) { 12 | pyo3::prepare_freethreaded_python(); 13 | 14 | Python::with_gil(|py| { 15 | let locals = PyDict::new(py); 16 | 17 | for i in imports { 18 | locals.set_item(i, py.import(i).unwrap()).unwrap(); 19 | } 20 | 21 | locals.set_item("INPUT", input).unwrap(); 22 | 23 | b.iter(|| black_box(py.run(code, None, Some(&locals)).unwrap())); 24 | }); 25 | } 26 | 27 | fn json_input(count: u64) -> String { 28 | let mut s = String::new(); 29 | let mut rng = thread_rng(); 30 | 31 | for _ in 0..count { 32 | let value: u16 = rng.gen(); 33 | let name: String = iter::repeat(()) 34 | .map(|()| rng.sample(Alphanumeric)) 35 | .map(char::from) 36 | .take(7) 37 | .collect(); 38 | 39 | writeln!(&mut s, r#"{{ "name": "{}", "value": {} }}"#, name, value) 40 | .unwrap(); 41 | } 42 | 43 | s 44 | } 45 | 46 | fn json_group(c: &mut Criterion) { 47 | let count = 1; 48 | 49 | let input = json_input(count); 50 | 51 | let mut group = c.benchmark_group("json"); 52 | group.throughput(Throughput::Elements(count)); 53 | 54 | group.bench_function("python-json", |b| { 55 | bench_py( 56 | &input, 57 | &["json"], 58 | "s = 0 59 | for line in INPUT.splitlines(): 60 | value = json.loads(line) 61 | s += value['value'] 62 | s += len(value['name'])", 63 | b, 64 | ) 65 | }); 66 | 67 | group.bench_function("PyO3-serde-json", |b| { 68 | bench_py( 69 | &input, 70 | &["rust_json"], 71 | "s = 0 72 | for line in INPUT.splitlines(): 73 | s += rust_json.sum(line)", 74 | b, 75 | ) 76 | }); 77 | 78 | drop(group); 79 | 80 | c.bench_function("python-raw", |b| { 81 | bench_py(&input, &["json"], "1 + 1", b) 82 | }); 83 | } 84 | 85 | criterion_group!( 86 | name = benches; 87 | config = Criterion::default().measurement_time(Duration::from_secs(10)); 88 | targets = json_group 89 | ); 90 | criterion_main!(benches); 91 | -------------------------------------------------------------------------------- /chapter-06/listing_01_benching/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | #[test] 4 | fn it_works() { 5 | assert_eq!(2 + 2, 4); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /chapter-06/listing_01_python_example/data.jsonl: -------------------------------------------------------------------------------- 1 | { "name": "Stokes Baker", "value": 954832 } 2 | { "name": "Joseph Solomon", "value": 279836 } 3 | { "name": "Gonzalez Koch", "value": 140431 } 4 | { "name": "Parrish Waters", "value": 490411 } 5 | { "name": "Sharlene Nunez", "value": 889667 } 6 | { "name": "Meadows David", "value": 892040 } 7 | { "name": "Whitley Mendoza", "value": 965462 } 8 | { "name": "Santiago Hood", "value": 280041 } 9 | { "name": "Carver Caldwell", "value": 632926 } 10 | { "name": "Tara Patterson", "value": 678175 } 11 | -------------------------------------------------------------------------------- /chapter-06/listing_01_python_example/main.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import json 3 | 4 | s = 0 5 | 6 | for line in sys.stdin: 7 | value = json.loads(line) 8 | s += value['value'] 9 | s += len(value['name']) 10 | 11 | print(s) 12 | -------------------------------------------------------------------------------- /chapter-06/listing_02_python_code_finished/main.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import rust_json 3 | 4 | s = 0 5 | 6 | for line in sys.stdin: 7 | s += rust_json.sum(line) 8 | 9 | print(s) 10 | -------------------------------------------------------------------------------- /chapter-06/listing_03_rust_psuedocode_NO_COMPILE/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-06-listing-03" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /chapter-06/listing_03_rust_psuedocode_NO_COMPILE/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub fn sum(line: &str) -> i32 { 2 | let data = parse_as_json(line); 3 | 4 | data.value + data.name.len() 5 | } 6 | -------------------------------------------------------------------------------- /chapter-06/listing_04_json_parser_first_pass_NO_COMPILE/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-06-listing-04" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | [dependencies] 8 | serde_json = "1.0" 9 | serde = { version = "1.0", features = ["derive"] } 10 | -------------------------------------------------------------------------------- /chapter-06/listing_04_json_parser_first_pass_NO_COMPILE/src/main.rs: -------------------------------------------------------------------------------- 1 | struct Data { 2 | name: String, 3 | value: i32, 4 | } 5 | 6 | fn main() { 7 | let input = "{ \"name\": \"Sharpe Oliver\", \"value\": 134087 }"; 8 | 9 | let parsed = serde_json::from_str(input).unwrap(); 10 | 11 | println!("{:?}", parsed); 12 | } 13 | -------------------------------------------------------------------------------- /chapter-06/listing_05_json_parser_working/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-06-listing-05" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | [dependencies] 8 | serde_json = "1.0" 9 | serde = { version = "1.0", features = ["derive"] } 10 | -------------------------------------------------------------------------------- /chapter-06/listing_05_json_parser_working/src/main.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, serde::Deserialize)] 2 | struct Data { 3 | name: String, 4 | value: i32, 5 | } 6 | 7 | fn main() { 8 | let input = "{ \"name\": \"Sharpe Oliver\", \"value\": 134087 }"; 9 | 10 | let parsed: Data = serde_json::from_str(input).unwrap(); 11 | 12 | println!("{:?}", parsed); 13 | } 14 | -------------------------------------------------------------------------------- /chapter-06/listing_06_json_parser_wrong_types/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-06-listing-06" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | [dependencies] 8 | serde_json = "1.0" 9 | serde = { version = "1.0", features = ["derive"] } 10 | -------------------------------------------------------------------------------- /chapter-06/listing_06_json_parser_wrong_types/src/main.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, serde::Deserialize)] 2 | struct Data { 3 | name: i32, 4 | value: i32, 5 | } 6 | 7 | fn main() { 8 | let input = "{ \"name\": \"Sharpe Oliver\", \"value\": 134087 }"; 9 | 10 | let parsed: Data = serde_json::from_str(input).unwrap(); 11 | 12 | println!("{:?}", parsed); 13 | } 14 | -------------------------------------------------------------------------------- /chapter-06/listing_07_json_summer_rust/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-06-listing-07" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | [dependencies] 8 | serde_json = "1.0.68" 9 | serde = { version = "1.0.130", features = ["derive"] } 10 | -------------------------------------------------------------------------------- /chapter-06/listing_07_json_summer_rust/src/main.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, serde::Deserialize)] 2 | struct Data { 3 | name: String, 4 | value: i32, 5 | } 6 | 7 | fn main() { 8 | let result = 9 | sum("{ \"name\": \"Rachelle Ferguson\", \"value\": 948129 }"); 10 | 11 | println!("{}", result); 12 | } 13 | 14 | fn sum(input: &str) -> i32 { 15 | let parsed: Data = serde_json::from_str(input).unwrap(); 16 | 17 | parsed.name.len() as i32 + parsed.value 18 | } 19 | -------------------------------------------------------------------------------- /chapter-06/listing_08_rust_json_lib/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-06-listing-08" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | [lib] 7 | name = "rust_json" 8 | crate-type = ["cdylib"] 9 | 10 | [dependencies] 11 | serde_json = "1.0.68" 12 | serde = { version = "1.0.130", features = ["derive"] } 13 | pyo3 = { version = "0.14", features = ["extension-module"] } 14 | -------------------------------------------------------------------------------- /chapter-06/listing_08_rust_json_lib/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, serde::Deserialize)] 2 | struct Data { 3 | name: String, 4 | value: i32, 5 | } 6 | 7 | fn sum(input: &str) -> i32 { 8 | let parsed: Data = serde_json::from_str(input).unwrap(); 9 | 10 | parsed.name.len() as i32 + parsed.value 11 | } 12 | -------------------------------------------------------------------------------- /chapter-06/listing_09_rust_json_empty_pymodule/.gitignore: -------------------------------------------------------------------------------- 1 | rust-json 2 | -------------------------------------------------------------------------------- /chapter-06/listing_09_rust_json_empty_pymodule/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-06-listing-09" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | [lib] 7 | name = "rust_json" 8 | crate-type = ["cdylib"] 9 | 10 | [dependencies] 11 | serde_json = "1.0.68" 12 | serde = { version = "1.0.130", features = ["derive"] } 13 | pyo3 = { version = "0.14", features = ["extension-module"] } 14 | -------------------------------------------------------------------------------- /chapter-06/listing_09_rust_json_empty_pymodule/run: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | virtualenv rust-json 4 | 5 | source rust-json/bin/activate 6 | 7 | maturin develop 8 | 9 | python 10 | -------------------------------------------------------------------------------- /chapter-06/listing_09_rust_json_empty_pymodule/src/lib.rs: -------------------------------------------------------------------------------- 1 | use pyo3::prelude::*; 2 | 3 | #[derive(Debug, serde::Deserialize)] 4 | struct Data { 5 | name: String, 6 | value: i32, 7 | } 8 | 9 | fn sum(input: &str) -> i32 { 10 | let parsed: Data = serde_json::from_str(input).unwrap(); 11 | 12 | parsed.name.len() as i32 + parsed.value 13 | } 14 | 15 | #[pymodule] 16 | fn rust_json(_py: Python, m: &PyModule) -> PyResult<()> { 17 | Ok(()) 18 | } 19 | -------------------------------------------------------------------------------- /chapter-06/listing_10_rust_json_wrapped_pyfunction/.gitignore: -------------------------------------------------------------------------------- 1 | rust-json 2 | -------------------------------------------------------------------------------- /chapter-06/listing_10_rust_json_wrapped_pyfunction/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-06-listing-10" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | [lib] 7 | name = "rust_json" 8 | crate-type = ["cdylib"] 9 | 10 | [dependencies] 11 | serde_json = "1.0.68" 12 | serde = { version = "1.0.130", features = ["derive"] } 13 | pyo3 = { version = "0.14", features = ["extension-module"] } 14 | -------------------------------------------------------------------------------- /chapter-06/listing_10_rust_json_wrapped_pyfunction/run: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | virtualenv rust-json 4 | 5 | source rust-json/bin/activate 6 | 7 | maturin develop 8 | 9 | python 10 | -------------------------------------------------------------------------------- /chapter-06/listing_10_rust_json_wrapped_pyfunction/src/lib.rs: -------------------------------------------------------------------------------- 1 | use pyo3::prelude::*; 2 | 3 | #[derive(Debug, serde::Deserialize)] 4 | struct Data { 5 | name: String, 6 | value: i32, 7 | } 8 | 9 | #[pyfunction] 10 | fn sum(input: &str) -> i32 { 11 | let parsed: Data = serde_json::from_str(input).unwrap(); 12 | 13 | parsed.name.len() as i32 + parsed.value 14 | } 15 | 16 | #[pymodule] 17 | fn rust_json(_py: Python, m: &PyModule) -> PyResult<()> { 18 | m.add_function(wrap_pyfunction!(sum, m)?)?; 19 | 20 | Ok(()) 21 | } 22 | -------------------------------------------------------------------------------- /chapter-06/listing_11_python_with_rust/data.jsonl: -------------------------------------------------------------------------------- 1 | { "name": "Stokes Baker", "value": 954832 } 2 | { "name": "Joseph Solomon", "value": 279836 } 3 | { "name": "Gonzalez Koch", "value": 140431 } 4 | { "name": "Parrish Waters", "value": 490411 } 5 | { "name": "Sharlene Nunez", "value": 889667 } 6 | { "name": "Meadows David", "value": 892040 } 7 | { "name": "Whitley Mendoza", "value": 965462 } 8 | { "name": "Santiago Hood", "value": 280041 } 9 | { "name": "Carver Caldwell", "value": 632926 } 10 | { "name": "Tara Patterson", "value": 678175 } 11 | -------------------------------------------------------------------------------- /chapter-06/listing_11_python_with_rust/main.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import json 3 | import rust_json 4 | 5 | s = 0 6 | 7 | for line in sys.stdin: 8 | s += rust_json.sum(line) 9 | 10 | print(s) 11 | -------------------------------------------------------------------------------- /chapter-06/listing_12_dev_dependencies_NO_COMPILE/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-06-listing-12" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | [[bench]] 7 | name = "py-vs-rust" 8 | harness = false 9 | 10 | [dependencies] 11 | 12 | [dev-dependencies] 13 | criterion = "0.3.5" 14 | pyo3 = { version = "0.14", features = ["auto-initialize"] } 15 | -------------------------------------------------------------------------------- /chapter-06/listing_12_dev_dependencies_NO_COMPILE/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | #[test] 4 | fn it_works() { 5 | assert_eq!(2 + 2, 4); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /chapter-06/listing_13_bench_base/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-06-listing-13" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | [[bench]] 7 | name = "py-vs-rust" 8 | harness = false 9 | 10 | [dependencies] 11 | 12 | [dev-dependencies] 13 | criterion = "0.3.5" 14 | pyo3 = { version = "0.14", features = ["auto-initialize"] } 15 | -------------------------------------------------------------------------------- /chapter-06/listing_13_bench_base/benches/py-vs-rust.rs: -------------------------------------------------------------------------------- 1 | use criterion::{black_box, criterion_group, criterion_main, Criterion}; 2 | 3 | criterion_main!(python_vs_rust); 4 | criterion_group!(python_vs_rust, bench_fn); 5 | 6 | fn bench_fn(c: &mut Criterion) { 7 | c.bench_function("u8", |b| { 8 | b.iter(|| { 9 | black_box(3u8 + 4); 10 | }); 11 | }); 12 | 13 | c.bench_function("u128", |b| { 14 | b.iter(|| { 15 | black_box(3u128 + 4); 16 | }); 17 | }); 18 | } 19 | -------------------------------------------------------------------------------- /chapter-06/listing_13_bench_base/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | #[test] 4 | fn it_works() { 5 | assert_eq!(2 + 2, 4); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /chapter-06/listing_14_bench_rust_sum/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-06-listing-14" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | [[bench]] 7 | name = "py-vs-rust" 8 | harness = false 9 | 10 | [dependencies] 11 | 12 | [dev-dependencies] 13 | criterion = "0.3.5" 14 | pyo3 = { version = "0.14", features = ["auto-initialize"] } 15 | -------------------------------------------------------------------------------- /chapter-06/listing_14_bench_rust_sum/benches/py-vs-rust.rs: -------------------------------------------------------------------------------- 1 | use criterion::{ 2 | black_box, criterion_group, criterion_main, Bencher, Criterion, 3 | }; 4 | use pyo3::prelude::*; 5 | use pyo3::types::PyDict; 6 | 7 | criterion_main!(python_vs_rust); 8 | criterion_group!(python_vs_rust, bench_fn); 9 | 10 | fn bench_py(b: &mut Bencher, code: &str, input: &str) { 11 | Python::with_gil(|py| { 12 | let locals = PyDict::new(py); 13 | 14 | locals.set_item("json", py.import("json").unwrap()).unwrap(); 15 | locals 16 | .set_item("rust_json", py.import("rust_json").unwrap()) 17 | .unwrap(); 18 | locals.set_item("INPUT", input).unwrap(); 19 | 20 | b.iter(|| black_box(py.run(code, None, Some(&locals)).unwrap())); 21 | }); 22 | } 23 | 24 | fn bench_fn(c: &mut Criterion) { 25 | let input = r#"{"name": "lily", "value": 42}"#; 26 | 27 | c.bench_function("pure python", |b| { 28 | bench_py( 29 | b, 30 | " 31 | value = json.loads(INPUT) 32 | s = value['value'] + len(value['name']) 33 | ", 34 | input, 35 | ); 36 | }); 37 | 38 | c.bench_function("rust extension library", |b| { 39 | bench_py(b, "s = rust_json.sum(INPUT)", input); 40 | }); 41 | } 42 | -------------------------------------------------------------------------------- /chapter-06/listing_14_bench_rust_sum/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | #[test] 4 | fn it_works() { 5 | assert_eq!(2 + 2, 4); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /chapter-07/listing_01_testing/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-07-listing-01" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /chapter-07/listing_01_testing/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | #[test] 4 | fn it_works() { 5 | let result = 2 + 2; 6 | assert_eq!(result, 4); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /chapter-07/listing_02_failing_test/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-07-listing-02" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /chapter-07/listing_02_failing_test/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | #[test] 4 | fn it_works() { 5 | let result = 2 + 2; 6 | assert_eq!(result, 4); 7 | } 8 | 9 | #[test] 10 | fn it_does_not_work() { 11 | let result = 2 + 2; 12 | assert_eq!(result, 5); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /chapter-07/listing_03_stdout/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-07-listing-03" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /chapter-07/listing_03_stdout/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | #[test] 4 | fn it_works() { 5 | eprintln!("it_works stderr"); 6 | println!("it_works stdout"); 7 | let result = 2 + 2; 8 | assert_eq!(result, 4); 9 | } 10 | 11 | #[test] 12 | fn it_does_not_work() { 13 | eprintln!("it_does_not_work stderr"); 14 | println!("it_does_not_work stdout"); 15 | let result = 2 + 2; 16 | assert_eq!(result, 5); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /chapter-07/listing_04_add_fn/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-07-listing-04" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /chapter-07/listing_04_add_fn/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Add together two i32 numbers and return the result of that addition 2 | pub fn add(x: i32, y: i32) -> i32 { 3 | x + y 4 | } 5 | 6 | #[cfg(test)] 7 | mod tests { 8 | #[test] 9 | fn it_works() { 10 | let result = 2 + 2; 11 | assert_eq!(result, 4); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /chapter-07/listing_05_add_fn_doc/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-07-listing-05" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | [dependencies] 8 | -------------------------------------------------------------------------------- /chapter-07/listing_05_add_fn_doc/src/lib.rs: -------------------------------------------------------------------------------- 1 | /// Add together two i32 numbers and return the result of that addition 2 | pub fn add(x: i32, y: i32) -> i32 { 3 | x + y 4 | } 5 | 6 | #[cfg(test)] 7 | mod tests { 8 | #[test] 9 | fn it_works() { 10 | let result = 2 + 2; 11 | assert_eq!(result, 4); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /chapter-07/listing_06_add_fn_doctest/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-07-listing-06" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | [dependencies] 8 | -------------------------------------------------------------------------------- /chapter-07/listing_06_add_fn_doctest/src/lib.rs: -------------------------------------------------------------------------------- 1 | /// Add together two i32 numbers and return the result of that addition 2 | /// ``` 3 | /// assert_eq!(chapter_07_listing_06::add(2, 2), 4); 4 | /// ``` 5 | /// 6 | /// ``` 7 | /// use chapter_07_listing_06::add; 8 | /// assert_eq!(add(2, 2), 5); 9 | /// ``` 10 | /// 11 | /// ``` 12 | /// use chapter_07_listing_06::add; 13 | /// assert_eq!(add("hello", 2), 4); 14 | /// ``` 15 | pub fn add(x: i32, y: i32) -> i32 { 16 | x + y 17 | } 18 | 19 | #[cfg(test)] 20 | mod tests { 21 | #[test] 22 | fn it_works() { 23 | let result = 2 + 2; 24 | assert_eq!(result, 4); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /chapter-07/listing_07_add_fn_passing_doctest/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-07-listing-07" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | [dependencies] 8 | -------------------------------------------------------------------------------- /chapter-07/listing_07_add_fn_passing_doctest/src/lib.rs: -------------------------------------------------------------------------------- 1 | /// Add together two i32 numbers and return the result of that addition 2 | /// ``` 3 | /// assert_eq!(chapter_07_listing_07::add(2, 2), 4); 4 | /// ``` 5 | /// 6 | /// ``` 7 | /// use chapter_07_listing_07::add; 8 | /// assert_eq!(add(3, 2), 5); 9 | /// ``` 10 | pub fn add(x: i32, y: i32) -> i32 { 11 | x + y 12 | } 13 | 14 | #[cfg(test)] 15 | mod tests { 16 | #[test] 17 | fn it_works() { 18 | let result = 2 + 2; 19 | assert_eq!(result, 4); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /chapter-07/listing_08_rust_json_reminder/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-07-listing-08" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | [lib] 7 | name = "rust_json" 8 | crate-type = ["cdylib"] 9 | 10 | [dependencies] 11 | serde_json = "1.0.68" 12 | serde = { version = "1.0.130", features = ["derive"] } 13 | pyo3 = { version = "0.14", features = ["extension-module"] } 14 | -------------------------------------------------------------------------------- /chapter-07/listing_08_rust_json_reminder/src/lib.rs: -------------------------------------------------------------------------------- 1 | use pyo3::prelude::*; 2 | 3 | #[derive(Debug, serde::Deserialize)] 4 | struct Data { 5 | name: String, 6 | value: i32, 7 | } 8 | 9 | #[pyfunction] 10 | fn sum(input: &str) -> i32 { 11 | let parsed: Data = serde_json::from_str(input).unwrap(); 12 | 13 | parsed.name.len() as i32 + parsed.value 14 | } 15 | 16 | #[pymodule] 17 | fn rust_json(_py: Python, m: &PyModule) -> PyResult<()> { 18 | m.add_function(wrap_pyfunction!(sum, m)?)?; 19 | 20 | Ok(()) 21 | } 22 | -------------------------------------------------------------------------------- /chapter-07/listing_09_rust_json_tests/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-07-listing-09" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | [lib] 7 | name = "rust_json" 8 | crate-type = ["cdylib"] 9 | 10 | [dependencies] 11 | serde_json = "1.0.68" 12 | serde = { version = "1.0.130", features = ["derive"] } 13 | pyo3 = { version = "0.14", features = ["extension-module"] } 14 | -------------------------------------------------------------------------------- /chapter-07/listing_09_rust_json_tests/src/lib.rs: -------------------------------------------------------------------------------- 1 | use pyo3::prelude::*; 2 | 3 | #[derive(Debug, serde::Deserialize)] 4 | struct Data { 5 | name: String, 6 | value: i32, 7 | } 8 | 9 | #[pyfunction] 10 | fn sum(input: &str) -> i32 { 11 | let parsed: Data = serde_json::from_str(input).unwrap(); 12 | 13 | parsed.name.len() as i32 + parsed.value 14 | } 15 | 16 | #[pymodule] 17 | fn rust_json(_py: Python, m: &PyModule) -> PyResult<()> { 18 | m.add_function(wrap_pyfunction!(sum, m)?)?; 19 | 20 | Ok(()) 21 | } 22 | 23 | #[cfg(test)] 24 | mod tests { 25 | use crate::sum; 26 | 27 | #[test] 28 | fn test_stokes_baker() { 29 | assert_eq!( 30 | sum("{ \"name\": \"Stokes Baker\", \"value\": 954832 }"), 31 | 954844 32 | ); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /chapter-07/listing_10_rust_json_raw_string/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-07-listing-10" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | [lib] 7 | name = "rust_json" 8 | crate-type = ["cdylib"] 9 | 10 | [dependencies] 11 | serde_json = "1.0.68" 12 | serde = { version = "1.0.130", features = ["derive"] } 13 | pyo3 = { version = "0.14", features = ["extension-module"] } 14 | -------------------------------------------------------------------------------- /chapter-07/listing_10_rust_json_raw_string/src/lib.rs: -------------------------------------------------------------------------------- 1 | use pyo3::prelude::*; 2 | 3 | #[derive(Debug, serde::Deserialize)] 4 | struct Data { 5 | name: String, 6 | value: i32, 7 | } 8 | 9 | #[pyfunction] 10 | fn sum(input: &str) -> i32 { 11 | let parsed: Data = serde_json::from_str(input).unwrap(); 12 | 13 | parsed.name.len() as i32 + parsed.value 14 | } 15 | 16 | #[pymodule] 17 | fn rust_json(_py: Python, m: &PyModule) -> PyResult<()> { 18 | m.add_function(wrap_pyfunction!(sum, m)?)?; 19 | 20 | Ok(()) 21 | } 22 | 23 | #[cfg(test)] 24 | mod tests { 25 | use crate::sum; 26 | 27 | #[test] 28 | fn test_stokes_baker() { 29 | assert_eq!( 30 | sum(r#"{ "name": "Stokes Baker", "value": 954832 }"#), 31 | 954844 32 | ); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /chapter-07/listing_11_more_rust_tests/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-07-listing-11" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | [lib] 7 | name = "rust_json" 8 | crate-type = ["cdylib"] 9 | 10 | [dependencies] 11 | serde_json = "1.0.68" 12 | serde = { version = "1.0.130", features = ["derive"] } 13 | pyo3 = { version = "0.14", features = ["extension-module"] } 14 | -------------------------------------------------------------------------------- /chapter-07/listing_11_more_rust_tests/src/lib.rs: -------------------------------------------------------------------------------- 1 | use pyo3::prelude::*; 2 | 3 | #[derive(Debug, serde::Deserialize)] 4 | struct Data { 5 | name: String, 6 | value: i32, 7 | } 8 | 9 | #[pyfunction] 10 | fn sum(input: &str) -> i32 { 11 | let parsed: Data = serde_json::from_str(input).unwrap(); 12 | 13 | parsed.name.len() as i32 + parsed.value 14 | } 15 | 16 | #[pymodule] 17 | fn rust_json(_py: Python, m: &PyModule) -> PyResult<()> { 18 | m.add_function(wrap_pyfunction!(sum, m)?)?; 19 | 20 | Ok(()) 21 | } 22 | 23 | #[cfg(test)] 24 | mod tests { 25 | use crate::sum; 26 | 27 | #[test] 28 | fn test_stokes_baker() { 29 | assert_eq!( 30 | sum(r#"{ "name": "Stokes Baker", "value": 954832 }"#), 31 | 954844 32 | ); 33 | } 34 | 35 | #[test] 36 | fn test_william_cavendish() { 37 | assert_eq!( 38 | sum(r#"{ "name": "William Cavendish", "value": -4011 }"#), 39 | -3994 40 | ); 41 | } 42 | 43 | #[test] 44 | fn test_ada_lovelace() { 45 | assert_eq!( 46 | sum(r#"{ "name": "Ada Lovelace", "value": 18151210 }"#), 47 | 18151222 48 | ); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /chapter-07/listing_12_python_lib/main.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import json 3 | 4 | s = 0 5 | 6 | for line in sys.stdin: 7 | value = json.loads(line) 8 | s += value['value'] 9 | s += len(value['name']) 10 | 11 | print(s) 12 | -------------------------------------------------------------------------------- /chapter-07/listing_13_python_lib_fn/main.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import json 3 | 4 | def sum(lines_iter): 5 | s = 0 6 | 7 | for line in lines_iter: 8 | value = json.loads(line) 9 | s += value['value'] 10 | s += len(value['name']) 11 | 12 | return s 13 | 14 | if __name__ == '__main__': 15 | print(sum(sys.stdin)) 16 | -------------------------------------------------------------------------------- /chapter-07/listing_14_python_pytest_initial/main.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import json 3 | 4 | def sum(lines_iter): 5 | s = 0 6 | 7 | for line in lines_iter: 8 | value = json.loads(line) 9 | s += value['value'] 10 | s += len(value['name']) 11 | 12 | return s 13 | 14 | if __name__ == '__main__': 15 | print(sum(sys.stdin)) 16 | -------------------------------------------------------------------------------- /chapter-07/listing_14_python_pytest_initial/main_test.py: -------------------------------------------------------------------------------- 1 | import main 2 | 3 | def test_10_lines(): 4 | lines = [ 5 | '{ "name": "Stokes Baker", "value": 954832 }', 6 | '{ "name": "Joseph Solomon", "value": 279836 }', 7 | '{ "name": "Gonzalez Koch", "value": 140431 }', 8 | '{ "name": "Parrish Waters", "value": 490411 }', 9 | '{ "name": "Sharlene Nunez", "value": 889667 }', 10 | '{ "name": "Meadows David", "value": 892040 }', 11 | '{ "name": "Whitley Mendoza", "value": 965462 }', 12 | '{ "name": "Santiago Hood", "value": 280041 }', 13 | '{ "name": "Carver Caldwell", "value": 632926 }', 14 | '{ "name": "Tara Patterson", "value": 678175 }', 15 | ] 16 | 17 | assert main.sum(lines) == 6203958 18 | -------------------------------------------------------------------------------- /chapter-07/listing_15_python_pytest_failing/main.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import json 3 | 4 | def sum(lines_iter): 5 | s = 0 6 | 7 | for line in lines_iter: 8 | value = json.loads(line) 9 | s += value['value'] 10 | s += len(value['name']) 11 | 12 | return s + 1 13 | 14 | if __name__ == '__main__': 15 | print(sum(sys.stdin)) 16 | -------------------------------------------------------------------------------- /chapter-07/listing_15_python_pytest_failing/main_test.py: -------------------------------------------------------------------------------- 1 | import main 2 | 3 | def test_10_lines(): 4 | lines = [ 5 | '{ "name": "Stokes Baker", "value": 954832 }', 6 | '{ "name": "Joseph Solomon", "value": 279836 }', 7 | '{ "name": "Gonzalez Koch", "value": 140431 }', 8 | '{ "name": "Parrish Waters", "value": 490411 }', 9 | '{ "name": "Sharlene Nunez", "value": 889667 }', 10 | '{ "name": "Meadows David", "value": 892040 }', 11 | '{ "name": "Whitley Mendoza", "value": 965462 }', 12 | '{ "name": "Santiago Hood", "value": 280041 }', 13 | '{ "name": "Carver Caldwell", "value": 632926 }', 14 | '{ "name": "Tara Patterson", "value": 678175 }', 15 | ] 16 | 17 | assert main.sum(lines) == 6203958 18 | -------------------------------------------------------------------------------- /chapter-07/listing_16_python_rust/main.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | import rust_json 4 | 5 | def sum(lines_iter): 6 | s = 0 7 | 8 | for line in lines_iter: 9 | s += rust_json.sum(line) 10 | 11 | return s 12 | 13 | if __name__ == '__main__': 14 | print(sum(sys.stdin)) 15 | -------------------------------------------------------------------------------- /chapter-07/listing_16_python_rust/main_test.py: -------------------------------------------------------------------------------- 1 | import main 2 | 3 | def test_10_lines(): 4 | lines = [ 5 | '{ "name": "Stokes Baker", "value": 954832 }', 6 | '{ "name": "Joseph Solomon", "value": 279836 }', 7 | '{ "name": "Gonzalez Koch", "value": 140431 }', 8 | '{ "name": "Parrish Waters", "value": 490411 }', 9 | '{ "name": "Sharlene Nunez", "value": 889667 }', 10 | '{ "name": "Meadows David", "value": 892040 }', 11 | '{ "name": "Whitley Mendoza", "value": 965462 }', 12 | '{ "name": "Santiago Hood", "value": 280041 }', 13 | '{ "name": "Carver Caldwell", "value": 632926 }', 14 | '{ "name": "Tara Patterson", "value": 678175 }', 15 | ] 16 | 17 | assert main.sum(lines) == 6203958 18 | -------------------------------------------------------------------------------- /chapter-07/listing_17_python_rust_monkeypatching/main.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | import rust_json 4 | 5 | def sum(lines_iter): 6 | s = 0 7 | 8 | for line in lines_iter: 9 | s += rust_json.sum(line) 10 | 11 | return s 12 | 13 | if __name__ == '__main__': 14 | print(sum(sys.stdin)) 15 | -------------------------------------------------------------------------------- /chapter-07/listing_17_python_rust_monkeypatching/main_test.py: -------------------------------------------------------------------------------- 1 | from pytest import MonkeyPatch 2 | 3 | import main 4 | 5 | def test_10_lines(): 6 | lines = [ 7 | '{ "name": "Stokes Baker", "value": 954832 }', 8 | '{ "name": "Joseph Solomon", "value": 279836 }', 9 | '{ "name": "Gonzalez Koch", "value": 140431 }', 10 | '{ "name": "Parrish Waters", "value": 490411 }', 11 | '{ "name": "Sharlene Nunez", "value": 889667 }', 12 | '{ "name": "Meadows David", "value": 892040 }', 13 | '{ "name": "Whitley Mendoza", "value": 965462 }', 14 | '{ "name": "Santiago Hood", "value": 280041 }', 15 | '{ "name": "Carver Caldwell", "value": 632926 }', 16 | '{ "name": "Tara Patterson", "value": 678175 }', 17 | ] 18 | 19 | assert main.sum(lines) == 6203958 20 | 21 | def test_compare_py_rust(): 22 | compare_py_and_rust( 23 | ['{ "name": "Stokes Baker", "value": 954832 }'] 24 | ) 25 | 26 | def python_sum(line): 27 | import json 28 | 29 | value = json.loads(line) 30 | return value['value'] + len(value['name']) 31 | 32 | def compare_py_and_rust(input): 33 | rust_result = main.sum(input) 34 | 35 | with MonkeyPatch.context() as m: 36 | m.setattr(main.rust_json, 'sum', python_sum) 37 | py_result = main.sum(input) 38 | 39 | assert rust_result == py_result 40 | -------------------------------------------------------------------------------- /chapter-07/listing_18_add_bug_to_rust/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chapter-07-listing-18" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | [lib] 7 | name = "rust_json" 8 | crate-type = ["cdylib"] 9 | 10 | [dependencies] 11 | serde_json = "1.0.68" 12 | serde = { version = "1.0.130", features = ["derive"] } 13 | pyo3 = { version = "0.14", features = ["extension-module"] } 14 | -------------------------------------------------------------------------------- /chapter-07/listing_18_add_bug_to_rust/src/lib.rs: -------------------------------------------------------------------------------- 1 | use pyo3::prelude::*; 2 | 3 | #[derive(Debug, serde::Deserialize)] 4 | struct Data { 5 | name: String, 6 | value: i32, 7 | } 8 | 9 | #[pyfunction] 10 | fn sum(input: &str) -> i32 { 11 | let parsed: Data = serde_json::from_str(input).unwrap(); 12 | 13 | parsed.name.len() as i32 + parsed.value + 10 14 | } 15 | 16 | #[pymodule] 17 | fn rust_json(_py: Python, m: &PyModule) -> PyResult<()> { 18 | m.add_function(wrap_pyfunction!(sum, m)?)?; 19 | 20 | Ok(()) 21 | } 22 | 23 | #[cfg(test)] 24 | mod tests { 25 | use crate::sum; 26 | 27 | #[test] 28 | fn test_stokes_baker() { 29 | assert_eq!( 30 | sum(r#"{ "name": "Stokes Baker", "value": 954832 }"#), 31 | 954844 32 | ); 33 | } 34 | 35 | #[test] 36 | fn test_william_cavendish() { 37 | assert_eq!( 38 | sum(r#"{ "name": "William Cavendish", "value": -4011 }"#), 39 | -3994 40 | ); 41 | } 42 | 43 | #[test] 44 | fn test_ada_lovelace() { 45 | assert_eq!( 46 | sum(r#"{ "name": "Ada Lovelace", "value": 18151210 }"#), 47 | 18151222 48 | ); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /chapter-07/listing_18_python_rust_monkeypatching_with_runner/main.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | import rust_json 4 | 5 | def sum(lines_iter): 6 | s = 0 7 | 8 | for line in lines_iter: 9 | s += rust_json.sum(line) 10 | 11 | return s 12 | 13 | if __name__ == '__main__': 14 | print(sum(sys.stdin)) 15 | -------------------------------------------------------------------------------- /chapter-07/listing_18_python_rust_monkeypatching_with_runner/main_test.py: -------------------------------------------------------------------------------- 1 | import main 2 | 3 | def test_10_lines(): 4 | lines = [ 5 | '{ "name": "Stokes Baker", "value": 954832 }', 6 | '{ "name": "Joseph Solomon", "value": 279836 }', 7 | '{ "name": "Gonzalez Koch", "value": 140431 }', 8 | '{ "name": "Parrish Waters", "value": 490411 }', 9 | '{ "name": "Sharlene Nunez", "value": 889667 }', 10 | '{ "name": "Meadows David", "value": 892040 }', 11 | '{ "name": "Whitley Mendoza", "value": 965462 }', 12 | '{ "name": "Santiago Hood", "value": 280041 }', 13 | '{ "name": "Carver Caldwell", "value": 632926 }', 14 | '{ "name": "Tara Patterson", "value": 678175 }', 15 | ] 16 | 17 | assert main.sum(lines) == 6203958 18 | 19 | def test_compare_py_rust(monkeypatch): 20 | compare_py_and_rust( 21 | monkeypatch, 22 | ['{ "name": "Stokes Baker", "value": 954832 }'] 23 | ) 24 | 25 | def compare_py_and_rust(monkeypatch, input): 26 | rust_result = main.sum(input) 27 | 28 | def python_sum(line): 29 | import json 30 | 31 | value = json.loads(line) 32 | return value['value'] + len(value['name']) 33 | 34 | with monkeypatch.context() as m: 35 | m.setattr(main.rust_json, 'sum', python_sum) 36 | py_result = main.sum(input) 37 | 38 | assert rust_result == py_result 39 | -------------------------------------------------------------------------------- /chapter-07/listing_19_python_rust_randomized/main.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | import rust_json 4 | 5 | def sum(lines_iter): 6 | s = 0 7 | 8 | for line in lines_iter: 9 | s += rust_json.sum(line) 10 | 11 | return s 12 | 13 | if __name__ == '__main__': 14 | print(sum(sys.stdin)) 15 | -------------------------------------------------------------------------------- /chapter-07/listing_19_python_rust_randomized/main_test.py: -------------------------------------------------------------------------------- 1 | import json 2 | import string 3 | import random 4 | 5 | import main 6 | 7 | def test_10_lines(): 8 | lines = [ 9 | '{ "name": "Stokes Baker", "value": 954832 }', 10 | '{ "name": "Joseph Solomon", "value": 279836 }', 11 | '{ "name": "Gonzalez Koch", "value": 140431 }', 12 | '{ "name": "Parrish Waters", "value": 490411 }', 13 | '{ "name": "Sharlene Nunez", "value": 889667 }', 14 | '{ "name": "Meadows David", "value": 892040 }', 15 | '{ "name": "Whitley Mendoza", "value": 965462 }', 16 | '{ "name": "Santiago Hood", "value": 280041 }', 17 | '{ "name": "Carver Caldwell", "value": 632926 }', 18 | '{ "name": "Tara Patterson", "value": 678175 }', 19 | ] 20 | 21 | assert main.sum(lines) == 6203958 22 | 23 | def test_compare_py_rust(monkeypatch): 24 | compare_py_and_rust( 25 | monkeypatch, 26 | ['{ "name": "Stokes Baker", "value": 954832 }'] 27 | ) 28 | 29 | def test_random_inputs(monkeypatch): 30 | for _ in range(100): 31 | randomized_test_case(monkeypatch) 32 | 33 | def randomized_test_case(monkeypatch): 34 | number_of_lines = random.randint(100, 500) 35 | 36 | lines = [] 37 | for _ in range(number_of_lines): 38 | number_of_chars = random.randint(100, 200) 39 | 40 | lines.append(json.dumps({ 41 | 'name': ''.join(random.choices(string.ascii_lowercase, k=number_of_chars)), 42 | 'value': random.randint(0, 10_000), 43 | })) 44 | 45 | compare_py_and_rust(monkeypatch, lines) 46 | 47 | def compare_py_and_rust(monkeypatch, input): 48 | rust_result = main.sum(input) 49 | 50 | def python_sum(line): 51 | import json 52 | 53 | value = json.loads(line) 54 | return value['value'] + len(value['name']) 55 | 56 | with monkeypatch.context() as m: 57 | m.setattr(main.rust_json, 'sum', python_sum) 58 | py_result = main.sum(input) 59 | 60 | assert rust_result == py_result 61 | -------------------------------------------------------------------------------- /chapter-08/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /chapter-08/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "mandelbrot" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [lib] 7 | name = "mandelbrot" 8 | # "cdylib" is necessary to produce a shared library for Python to import from. 9 | crate-type = ["cdylib"] 10 | 11 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 12 | 13 | [dependencies] 14 | image = "0.24.7" 15 | num-complex = "0.4.4" 16 | 17 | [dependencies.pyo3] 18 | version = "0.20.0" 19 | # "abi3-py38" tells pyo3 (and maturin) to build using the stable ABI with minimum Python version 3.8 20 | features = ["abi3-py38"] 21 | -------------------------------------------------------------------------------- /chapter-08/main-async.py: -------------------------------------------------------------------------------- 1 | from PIL import Image 2 | import asyncio 3 | 4 | async def mandelbrot_func(size: int, path: str, range_x0: float, range_y0: float, range_x1: float, range_y1: float): 5 | image = Image.new(mode='RGB', size=(size, size)) 6 | 7 | size_f = float(size) 8 | 9 | x_range = abs(range_x1 - range_x0) 10 | x_offset = x_range / 2.0 11 | 12 | y_range = abs(range_y1 - range_y0) 13 | y_offset = y_range / 2.0 14 | 15 | for px in range(size): 16 | for py in range(size): 17 | x0 = float(px) / size_f * x_range - x_offset 18 | y0 = float(py) / size_f * y_range - y_offset 19 | 20 | c = complex(x0, y0) 21 | i = 0 22 | z = complex(0, 0) 23 | 24 | while i < 255: 25 | z = (z * z) + c 26 | if float(z.real) > 4.0: 27 | break 28 | i += 1 29 | 30 | image.putpixel((px, py), (i, i, i)) 31 | image.save(path) 32 | 33 | 34 | async def main(): 35 | await asyncio.gather(*[ 36 | mandelbrot_func(1000, f"purp{i}.png", -5.0, -2.12, -2.5, 1.12) 37 | for i in range(0,8) 38 | ]) 39 | 40 | asyncio.run(main()) 41 | -------------------------------------------------------------------------------- /chapter-08/main-mult.py: -------------------------------------------------------------------------------- 1 | from PIL import Image 2 | 3 | 4 | def mandelbrot(size: int, path: str, range_x0: float, range_y0: float, range_x1: float, range_y1: float): 5 | image = Image.new(mode='RGB', size=(size, size)) 6 | 7 | size_f = float(size) 8 | 9 | x_range = abs(range_x1 - range_x0) 10 | x_offset = x_range / 2.0 11 | 12 | y_range = abs(range_y1 - range_y0) 13 | y_offset = y_range / 2.0 14 | 15 | for px in range(size): 16 | for py in range(size): 17 | x0 = float(px) / size_f * x_range - x_offset 18 | y0 = float(py) / size_f * y_range - y_offset 19 | 20 | c = complex(x0, y0) 21 | i = 0 22 | z = complex(0, 0) 23 | 24 | while i < 255: 25 | z = (z * z) + c 26 | if float(z.real) > 4.0: 27 | break 28 | i += 1 29 | 30 | image.putpixel((px, py), (i, i, i)) 31 | image.save(path) 32 | 33 | def main(): 34 | for i in range(0,8): 35 | mandelbrot(1000, f"{i}.png", -5.0, -2.12, -2.5, 1.12) 36 | 37 | if __name__ == "__main__": 38 | main() 39 | -------------------------------------------------------------------------------- /chapter-08/main-single.py: -------------------------------------------------------------------------------- 1 | from PIL import Image 2 | 3 | 4 | def mandelbrot(size: int, path: str, range_x0: float, range_y0: float, range_x1: float, range_y1: float): 5 | image = Image.new(mode='RGB', size=(size, size)) 6 | 7 | size_f = float(size) 8 | 9 | x_range = abs(range_x1 - range_x0) 10 | x_offset = x_range / 2.0 11 | 12 | y_range = abs(range_y1 - range_y0) 13 | y_offset = y_range / 2.0 14 | 15 | for px in range(size): 16 | for py in range(size): 17 | x0 = float(px) / size_f * x_range - x_offset 18 | y0 = float(py) / size_f * y_range - y_offset 19 | 20 | c = complex(x0, y0) 21 | i = 0 22 | z = complex(0, 0) 23 | 24 | while i < 255: 25 | z = (z * z) + c 26 | if float(z.real) > 4.0: 27 | break 28 | i += 1 29 | 30 | image.putpixel((px, py), (i, i, i)) 31 | image.save(path) 32 | 33 | mandelbrot(1000, "purp.png", -5.0, -2.12, -2.5, 1.12) 34 | -------------------------------------------------------------------------------- /chapter-08/main-thread.py: -------------------------------------------------------------------------------- 1 | from PIL import Image 2 | from concurrent.futures import ThreadPoolExecutor 3 | import asyncio 4 | 5 | def mandelbrot_func(size: int, path: str, range_x0: float, range_y0: float, range_x1: float, range_y1: float): 6 | image = Image.new(mode='RGB', size=(size, size)) 7 | 8 | size_f = float(size) 9 | 10 | x_range = abs(range_x1 - range_x0) 11 | x_offset = x_range / 2.0 12 | 13 | y_range = abs(range_y1 - range_y0) 14 | y_offset = y_range / 2.0 15 | 16 | for px in range(size): 17 | for py in range(size): 18 | x0 = float(px) / size_f * x_range - x_offset 19 | y0 = float(py) / size_f * y_range - y_offset 20 | 21 | c = complex(x0, y0) 22 | i = 0 23 | z = complex(0, 0) 24 | 25 | while i < 255: 26 | z = (z * z) + c 27 | if float(z.real) > 4.0: 28 | break 29 | i += 1 30 | 31 | image.putpixel((px, py), (i, i, i)) 32 | image.save(path) 33 | 34 | executor = ThreadPoolExecutor(max_workers=4) 35 | 36 | async def mandelbrot(size: int, path: str, range_x0: float, range_y0: float, range_x1: float, range_y1: float): 37 | return executor.submit(mandelbrot_func, size, path, range_x0, range_y0, range_x1, range_y1) 38 | 39 | 40 | async def main(): 41 | await asyncio.gather(*[ 42 | mandelbrot(1000, f"purp{i}.png", -5.0, -2.12, -2.5, 1.12) 43 | for i in range(0,8) 44 | ]) 45 | 46 | asyncio.run(main()) 47 | -------------------------------------------------------------------------------- /chapter-08/main.py: -------------------------------------------------------------------------------- 1 | from mandelbrot import mandelbrot_func 2 | import asyncio 3 | 4 | 5 | async def mandelbrot(size: int, path: str, range_x0: float, range_y0: float, range_x1: float, range_y1: float): 6 | mandelbrot_func(size, path, range_x0, range_y0, range_x1, range_y1) 7 | print(f"{path} created") 8 | 9 | async def main(): 10 | await asyncio.gather(*[ 11 | mandelbrot(1000, f"purp{i}.png", -5.0, -2.12, -2.5, 1.12) 12 | for i in range(0,8) 13 | ]) 14 | 15 | asyncio.run(main()) 16 | -------------------------------------------------------------------------------- /chapter-08/main2.py: -------------------------------------------------------------------------------- 1 | from mandelbrot import mandelbrot_fast 2 | from concurrent.futures import ThreadPoolExecutor 3 | import asyncio 4 | 5 | executor = ThreadPoolExecutor(max_workers=4) 6 | 7 | async def mandelbrot(size: int, path: str, range_x0: float, range_y0: float, range_x1: float, range_y1: float): 8 | return executor.submit(mandelbrot_fast, size, path, range_x0, range_y0, range_x1, range_y1) 9 | 10 | async def main(): 11 | await asyncio.gather(*[ 12 | mandelbrot(1000, f"purp{i}.png", -5.0, -2.12, -2.5, 1.12) 13 | for i in range(0,8) 14 | ]) 15 | 16 | asyncio.run(main()) 17 | -------------------------------------------------------------------------------- /chapter-08/main3.py: -------------------------------------------------------------------------------- 1 | from mandelbrot import mandelbrot_func 2 | from concurrent.futures import ThreadPoolExecutor 3 | import asyncio 4 | 5 | executor = ThreadPoolExecutor(max_workers=4) 6 | 7 | async def mandelbrot(size: int, path: str, range_x0: float, range_y0: float, range_x1: float, range_y1: float): 8 | return executor.submit(mandelbrot_func, size, path, range_x0, range_y0, range_x1, range_y1) 9 | 10 | async def main(): 11 | await asyncio.gather(*[ 12 | mandelbrot(1000, f"purp{i}.png", -5.0, -2.12, -2.5, 1.12) 13 | for i in range(0,8) 14 | ]) 15 | 16 | asyncio.run(main()) 17 | -------------------------------------------------------------------------------- /chapter-08/pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["maturin>=1.0,<2.0"] 3 | build-backend = "maturin" 4 | 5 | [tool.maturin] 6 | # "extension-module" tells pyo3 we want to build an extension module (skips linking against libpython.so) 7 | features = ["pyo3/extension-module"] -------------------------------------------------------------------------------- /chapter-08/requirements.txt: -------------------------------------------------------------------------------- 1 | mandelbrot @ file:///var/folders/fn/8gbv4zs92lqc4zlftc11f2zw0000gn/T/.tmpOWxfjD/mandelbrot-0.1.0-cp38-abi3-macosx_11_0_arm64.whl#sha256=cb627ff6e1d00bfe20365e42f5cf56f29468c02b76977f42b26ccbda50c7a5b4 2 | maturin==1.4.0 3 | pillow==10.2.0 4 | -------------------------------------------------------------------------------- /chapter-08/src/lib.rs: -------------------------------------------------------------------------------- 1 | use image::{Rgb, RgbImage}; 2 | use num_complex::Complex64; 3 | use pyo3::prelude::*; 4 | use std::path::Path; 5 | 6 | #[pyfunction] 7 | fn mandelbrot_fast( 8 | py: Python<'_>, 9 | size: u32, 10 | path: &str, 11 | range_x0: f64, 12 | range_y0: f64, 13 | range_x1: f64, 14 | range_y1: f64, 15 | ) { 16 | py.allow_threads(|| mandelbrot_func(size, path, range_x0, range_y0, range_x1, range_y1)) 17 | } 18 | #[pyfunction] 19 | fn mandelbrot_func(size: u32, p: &str, range_x0: f64, range_y0: f64, range_x1: f64, range_y1: f64) { 20 | let mut img = RgbImage::new(size, size); 21 | 22 | let size_f64 = size as f64; 23 | 24 | let x_range = (range_x1 - range_x0).abs(); 25 | let x_offset = x_range / 2.0; 26 | 27 | let y_range = (range_y1 - range_y0).abs(); 28 | let y_offset = y_range / 2.0; 29 | let path = Path::new(p); 30 | for px in 0..size { 31 | for py in 0..size { 32 | let x0 = px as f64 / size_f64 * x_range - x_offset; 33 | let y0 = py as f64 / size_f64 * y_range - y_offset; 34 | 35 | let c = Complex64::new(x0, y0); 36 | 37 | let mut i = 0u8; 38 | let mut z = Complex64::new(0.0, 0.0); 39 | 40 | while i < 255 { 41 | z = (z * z) + c; 42 | if z.norm() > 4.0 { 43 | break; 44 | } 45 | i += 1; 46 | } 47 | 48 | img.put_pixel(px, py, Rgb([i, i, i])); 49 | } 50 | } 51 | 52 | img.save(path).unwrap(); 53 | } 54 | 55 | #[pymodule] 56 | fn mandelbrot(_py: Python, m: &PyModule) -> PyResult<()> { 57 | m.add_function(wrap_pyfunction!(mandelbrot_func, m)?)?; 58 | m.add_function(wrap_pyfunction!(mandelbrot_fast, m)?)?; 59 | 60 | Ok(()) 61 | } 62 | -------------------------------------------------------------------------------- /chapter-08/src/main.rs: -------------------------------------------------------------------------------- 1 | use image::{Rgb, RgbImage}; 2 | use num_complex::Complex64; 3 | use pyo3::prelude::*; 4 | use std::path::Path; 5 | 6 | #[pyfunction] 7 | fn mandelbrot_fast( 8 | py: Python<'_>, 9 | size: u32, 10 | path: str, 11 | range_x0: f64, 12 | range_y0: f64, 13 | range_x1: f64, 14 | range_y1: f64, 15 | ) { 16 | py.allow_threads(|| mandelbrot_func(size, path, range_x0, range_y0, range_x1, range_y1)) 17 | } 18 | #[pyfunction] 19 | fn mandelbrot_func(size: u32, p: str, range_x0: f64, range_y0: f64, range_x1: f64, range_y1: f64) { 20 | let mut img = RgbImage::new(size, size); 21 | 22 | let size_f64 = size as f64; 23 | 24 | let x_range = (range_x1 - range_x0).abs(); 25 | let x_offset = x_range / 2.0; 26 | 27 | let y_range = (range_y1 - range_y0).abs(); 28 | let y_offset = y_range / 2.0; 29 | let path = Path::new(p); 30 | for px in 0..size { 31 | for py in 0..size { 32 | let x0 = px as f64 / size_f64 * x_range - x_offset; 33 | let y0 = py as f64 / size_f64 * y_range - y_offset; 34 | 35 | let c = Complex64::new(x0, y0); 36 | 37 | let mut i = 0u8; 38 | let mut z = Complex64::new(0.0, 0.0); 39 | 40 | while i < 255 { 41 | z = (z * z) + c; 42 | if z.norm() > 4.0 { 43 | break; 44 | } 45 | i += 1; 46 | } 47 | 48 | img.put_pixel(px, py, Rgb([i, i, i])); 49 | } 50 | } 51 | 52 | img.save(path).unwrap(); 53 | } 54 | -------------------------------------------------------------------------------- /chapter-09/papers/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "papers" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | [lib] 8 | crate-type = ["cdylib"] 9 | 10 | [dependencies] 11 | reqwest = { version = "0.11", features = ["json"] } 12 | serde = { version = "1.0", features = ["derive"] } 13 | serde-wasm-bindgen = "0.5.0" 14 | # tokio = { version = "1", features = ["full"] } 15 | serde-xml-rs = "0.6.0" 16 | wasm-bindgen = "0.2" 17 | wasm-bindgen-futures = "0.4.37" 18 | yew = "0.19.0" 19 | 20 | [dev-dependencies] 21 | tokio-test = "*" 22 | -------------------------------------------------------------------------------- /chapter-09/papers/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Feed example 6 | 7 | 8 |
9 |
    10 |
    11 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /chapter-09/papers/papers-list/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { browser: true, es2020: true }, 3 | extends: [ 4 | 'eslint:recommended', 5 | 'plugin:react/recommended', 6 | 'plugin:react/jsx-runtime', 7 | 'plugin:react-hooks/recommended', 8 | ], 9 | parserOptions: { ecmaVersion: 'latest', sourceType: 'module' }, 10 | settings: { react: { version: '18.2' } }, 11 | plugins: ['react-refresh'], 12 | rules: { 13 | 'react-refresh/only-export-components': 'warn', 14 | }, 15 | } 16 | -------------------------------------------------------------------------------- /chapter-09/papers/papers-list/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /chapter-09/papers/papers-list/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + React 8 | 9 | 10 |
    11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /chapter-09/papers/papers-list/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "papers-list", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "vite build", 9 | "lint": "eslint src --ext js,jsx --report-unused-disable-directives --max-warnings 0", 10 | "preview": "vite preview" 11 | }, 12 | "dependencies": { 13 | "papers": "file:../pkg", 14 | "react": "^18.2.0", 15 | "react-dom": "^18.2.0" 16 | }, 17 | "devDependencies": { 18 | "@types/react": "^18.0.37", 19 | "@types/react-dom": "^18.0.11", 20 | "@vitejs/plugin-react": "^4.0.0", 21 | "eslint": "^8.38.0", 22 | "eslint-plugin-react": "^7.32.2", 23 | "eslint-plugin-react-hooks": "^4.6.0", 24 | "eslint-plugin-react-refresh": "^0.3.4", 25 | "vite": "^4.3.9", 26 | "vite-plugin-top-level-await": "^1.3.1", 27 | "vite-plugin-wasm": "^3.2.2" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /chapter-09/papers/papers-list/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /chapter-09/papers/papers-list/src/App.css: -------------------------------------------------------------------------------- 1 | #root { 2 | max-width: 1280px; 3 | margin: 0 auto; 4 | padding: 2rem; 5 | text-align: center; 6 | } 7 | 8 | .logo { 9 | height: 6em; 10 | padding: 1.5em; 11 | will-change: filter; 12 | transition: filter 300ms; 13 | } 14 | .logo:hover { 15 | filter: drop-shadow(0 0 2em #646cffaa); 16 | } 17 | .logo.react:hover { 18 | filter: drop-shadow(0 0 2em #61dafbaa); 19 | } 20 | 21 | @keyframes logo-spin { 22 | from { 23 | transform: rotate(0deg); 24 | } 25 | to { 26 | transform: rotate(360deg); 27 | } 28 | } 29 | 30 | @media (prefers-reduced-motion: no-preference) { 31 | a:nth-of-type(2) .logo { 32 | animation: logo-spin infinite 20s linear; 33 | } 34 | } 35 | 36 | .card { 37 | padding: 2em; 38 | } 39 | 40 | .read-the-docs { 41 | color: #888; 42 | } 43 | -------------------------------------------------------------------------------- /chapter-09/papers/papers-list/src/App.jsx: -------------------------------------------------------------------------------- 1 | import { useState } from 'react' 2 | import reactLogo from './assets/react.svg' 3 | import viteLogo from '/vite.svg' 4 | import './App.css' 5 | import List from './List' 6 | 7 | const wasm = await import('papers') 8 | 9 | function App() { 10 | const [count, setCount] = useState(0) 11 | 12 | return (
    13 |
    {wasm.list_component()}
    14 | 15 |
    16 | ) 17 | } 18 | 19 | export default App 20 | -------------------------------------------------------------------------------- /chapter-09/papers/papers-list/src/List.jsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from 'react' 2 | const wasm = await import('papers') 3 | 4 | const List = () => { 5 | const [entries, setEntries] = useState([]) 6 | const [page, setPage] = useState(0) 7 | useEffect(() => { 8 | if(wasm){ 9 | wasm.paper_search({"term":"type", "page": page, "limit": 10}).then( 10 | (result)=>setEntries(result.entry), 11 | (error)=>console.error(error)) 12 | } 13 | }, [page]) 14 | 15 | return ( 16 |
    17 |
      18 | {entries?.map((v, i) => { 19 | return
    • 20 | {v.title} 21 |
    • 22 | })} 23 |
    24 | 25 |
    26 | ) 27 | } 28 | export default List; -------------------------------------------------------------------------------- /chapter-09/papers/papers-list/src/index.css: -------------------------------------------------------------------------------- 1 | :root { 2 | font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; 3 | line-height: 1.5; 4 | font-weight: 400; 5 | 6 | color-scheme: light dark; 7 | color: rgba(255, 255, 255, 0.87); 8 | background-color: #242424; 9 | 10 | font-synthesis: none; 11 | text-rendering: optimizeLegibility; 12 | -webkit-font-smoothing: antialiased; 13 | -moz-osx-font-smoothing: grayscale; 14 | -webkit-text-size-adjust: 100%; 15 | } 16 | 17 | a { 18 | font-weight: 500; 19 | color: #646cff; 20 | text-decoration: inherit; 21 | } 22 | a:hover { 23 | color: #535bf2; 24 | } 25 | 26 | body { 27 | margin: 0; 28 | display: flex; 29 | place-items: center; 30 | min-width: 320px; 31 | min-height: 100vh; 32 | } 33 | 34 | h1 { 35 | font-size: 3.2em; 36 | line-height: 1.1; 37 | } 38 | 39 | button { 40 | border-radius: 8px; 41 | border: 1px solid transparent; 42 | padding: 0.6em 1.2em; 43 | font-size: 1em; 44 | font-weight: 500; 45 | font-family: inherit; 46 | background-color: #1a1a1a; 47 | cursor: pointer; 48 | transition: border-color 0.25s; 49 | } 50 | button:hover { 51 | border-color: #646cff; 52 | } 53 | button:focus, 54 | button:focus-visible { 55 | outline: 4px auto -webkit-focus-ring-color; 56 | } 57 | 58 | @media (prefers-color-scheme: light) { 59 | :root { 60 | color: #213547; 61 | background-color: #ffffff; 62 | } 63 | a:hover { 64 | color: #747bff; 65 | } 66 | button { 67 | background-color: #f9f9f9; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /chapter-09/papers/papers-list/src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom/client' 3 | import App from './App.jsx' 4 | import './index.css' 5 | 6 | ReactDOM.createRoot(document.getElementById('root')).render( 7 | 8 | 9 | , 10 | ) 11 | -------------------------------------------------------------------------------- /chapter-09/papers/papers-list/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | import wasm from "vite-plugin-wasm"; 4 | import topLevelAwait from "vite-plugin-top-level-await"; 5 | 6 | // https://vitejs.dev/config/ 7 | export default defineConfig({ 8 | plugins: [react(), 9 | wasm(), 10 | topLevelAwait()], 11 | }) 12 | -------------------------------------------------------------------------------- /chapter-10/journal/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | 3 | members = [ 4 | "paper_search", 5 | "paper_search_lib", 6 | "book_search" 7 | ] 8 | exclude = ["journal_cli"] -------------------------------------------------------------------------------- /chapter-10/journal/book_search/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /chapter-10/journal/book_search/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "book_search" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [build] 7 | target="wasm32-wasi" 8 | 9 | [target.wasm32-wasi] 10 | runner = "wasmedge" 11 | 12 | [dependencies] 13 | tokio_wasi = { version = "1.21", features = ["rt", "macros", "net", "time"]} 14 | reqwest_wasi = "0.11" 15 | serde = { version = "1.0", features = ["derive"] } 16 | serde_json = "1.0" -------------------------------------------------------------------------------- /chapter-10/journal/book_search/src/main.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | use std::env; 3 | use std::error::Error; 4 | use std::fmt::{self, Debug, Display, Formatter}; 5 | use std::os::raw::{c_void, c_int}; 6 | use std::mem; 7 | use std::ffi::{CStr, c_char, CString}; 8 | 9 | #[no_mangle] 10 | pub fn memory_search(term: *mut c_char) -> *mut c_char { 11 | let t = unsafe { CStr::from_ptr(term).to_bytes().to_vec() }; 12 | let mut output = t.to_vec(); 13 | let search_term: String = String::from_utf8(output).unwrap(); 14 | let res_string = search(search_term).unwrap(); 15 | let mut res: Vec = res_string.into_iter().nth(0).unwrap().into(); 16 | res.resize(1024, 0); 17 | unsafe { CString::from_vec_unchecked(res)}.into_raw() 18 | } 19 | 20 | #[no_mangle] 21 | pub extern fn allocate(size: usize) -> *mut c_void { 22 | let mut buffer = Vec::with_capacity(size); 23 | let pointer = buffer.as_mut_ptr(); 24 | mem::forget(buffer); 25 | 26 | pointer as *mut c_void 27 | } 28 | 29 | 30 | #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] 31 | pub struct SearchResult { 32 | pub results: Vec, 33 | } 34 | 35 | #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] 36 | pub struct Book { 37 | pub id: i32, 38 | pub title: String, 39 | } 40 | 41 | fn main() -> Result<(), Box> { 42 | let mut args: Vec = env::args().skip(1).collect(); 43 | args.reverse(); 44 | let term = args.pop().unwrap_or("rust".to_string()); 45 | 46 | let res: Vec = search(term).unwrap(); 47 | for entry in res.iter() { 48 | println!("{}", entry); 49 | } 50 | Ok(()) 51 | } 52 | pub fn search( 53 | term: String 54 | ) -> Result, Box> { 55 | let rt = tokio::runtime::Builder::new_current_thread() 56 | .enable_all() 57 | .build() 58 | .unwrap(); 59 | let searchresult: SearchResult = rt.block_on(async {call_api(term) 60 | .await}).unwrap(); 61 | let res = searchresult 62 | .results 63 | .into_iter() 64 | .map(|e| format!("{}", e.title)) 65 | .collect::>(); 66 | return Ok::, Box>(res); 67 | } 68 | 69 | pub async fn call_api(term: String) -> Result { 70 | let http_response = reqwest::get(format!( 71 | "http://gutendex.com/books/?search={}", 72 | term 73 | )) 74 | .await?; 75 | let b = http_response.text().await?; 76 | let res: SearchResult = serde_json::from_str(b.as_str()).unwrap(); 77 | return Ok(res); 78 | } -------------------------------------------------------------------------------- /chapter-10/journal/book_search/src/main1.bak: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | use std::env; 3 | use std::error::Error; 4 | use std::fmt::{self, Debug, Display, Formatter}; 5 | 6 | 7 | #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] 8 | pub struct SearchResult { 9 | pub results: Vec, 10 | } 11 | 12 | #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] 13 | pub struct Book { 14 | pub id: i32, 15 | pub title: String, 16 | } 17 | 18 | fn main() -> Result<(), Box> { 19 | let mut args: Vec = env::args().skip(1).collect(); 20 | args.reverse(); 21 | let term = args.pop().unwrap_or("rust".to_string()); 22 | 23 | let res: Vec = search(term).unwrap(); 24 | for entry in res.iter() { 25 | println!("{}", entry); 26 | } 27 | Ok(()) 28 | } 29 | pub fn search( 30 | term: String 31 | ) -> Result, Box> { 32 | let rt = tokio::runtime::Builder::new_current_thread() 33 | .enable_all() 34 | .build() 35 | .unwrap(); 36 | let searchresult: SearchResult = rt.block_on(async {call_api(term) 37 | .await}).unwrap(); 38 | let res = searchresult 39 | .results 40 | .into_iter() 41 | .map(|e| format!("{}", e.title)) 42 | .collect::>(); 43 | return Ok::, Box>(res); 44 | } 45 | 46 | pub async fn call_api(term: String) -> Result { 47 | let http_response = reqwest::get(format!( 48 | "http://gutendex.com/books/?search={}", 49 | term 50 | )) 51 | .await?; 52 | let b = http_response.text().await?; 53 | let res: SearchResult = serde_json::from_str(b.as_str()).unwrap(); 54 | return Ok(res); 55 | } -------------------------------------------------------------------------------- /chapter-10/journal/journal_cli/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /chapter-10/journal/journal_cli/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "journal_cli" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | wasmedge-sdk = "0.11.2" -------------------------------------------------------------------------------- /chapter-10/journal/journal_cli/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | use std::path::PathBuf; 3 | use wasmedge_sdk::{ 4 | config::{CommonConfigOptions, ConfigBuilder, HostRegistrationConfigOptions}, 5 | params, VmBuilder, WasmVal 6 | }; 7 | 8 | fn main() -> Result<(), Box>{ 9 | let mut args: Vec = env::args().skip(1).collect(); 10 | args.reverse(); 11 | let target = args.pop().unwrap_or("paper_search".to_string()); 12 | let filename = format!("{}.wasm", target); 13 | let wasm_file: PathBuf = ["..", "target", "wasm32-wasi", "debug", filename.as_str()].iter().collect(); 14 | 15 | // create a config with the `wasi` option enabled 16 | let config = ConfigBuilder::new(CommonConfigOptions::default()) 17 | .with_host_registration_config(HostRegistrationConfigOptions::default().wasi(true)) 18 | .build()?; 19 | assert!(config.wasi_enabled()); 20 | 21 | // create a VM with the config 22 | let term = args.pop().unwrap_or("type".to_string()); 23 | let mut vm = VmBuilder::new().with_config(config).build()?; 24 | 25 | vm.wasi_module_mut() 26 | .expect("Not found wasi module") 27 | .initialize(None, None, None); 28 | let m = vm.clone() 29 | .register_module_from_file(target.to_string(), &wasm_file)?; 30 | let env_instance = m.named_module(target.to_string())?; 31 | 32 | let exec = vm.executor(); 33 | 34 | let mut memory = env_instance.memory("memory")?; 35 | let allocate = env_instance.func("allocate")?; 36 | let search = env_instance.func("memory_search")?; 37 | 38 | let term_len: i32 = term.len() as i32; 39 | let iptr = allocate.run(exec, params!(term_len))?[0].to_i32(); 40 | let uptr: u32 = iptr as u32; 41 | memory.write(term, uptr); 42 | 43 | let iresptr = search.run(exec, params!(iptr))?[0].to_i32(); 44 | let uresptr: u32 = iresptr as u32; 45 | let val = memory.read_string(uresptr, 1024)?; 46 | let val = val.trim_matches(char::from(0)); 47 | 48 | println!("{:?}", val); 49 | Ok(()) 50 | } -------------------------------------------------------------------------------- /chapter-10/journal/journal_cli/src/main1.bak: -------------------------------------------------------------------------------- 1 | use std::env; 2 | use std::path::PathBuf; 3 | use wasmedge_sdk::{ 4 | config::{CommonConfigOptions, ConfigBuilder, HostRegistrationConfigOptions}, 5 | params, VmBuilder, WasmVal 6 | }; 7 | 8 | fn main() -> Result<(), Box>{ 9 | let mut args: Vec = env::args().skip(1).collect(); 10 | args.reverse(); 11 | let target = args.pop().unwrap_or("paper_search".to_string()); 12 | let filename = format!("{}.wasm", target); 13 | let wasm_file: PathBuf = ["..", "target", "wasm32-wasi", "debug", filename.as_str()].iter().collect(); 14 | //Create a config with the `wasi` option enabled 15 | let config = ConfigBuilder::new(CommonConfigOptions::default()) 16 | .with_host_registration_config(HostRegistrationConfigOptions::default().wasi(true)) 17 | .build()?; 18 | assert!(config.wasi_enabled()); 19 | 20 | // create a VM with the config 21 | let mut vm = VmBuilder::new().with_config(config).build()?; 22 | 23 | vm.wasi_module_mut() 24 | .expect("Not found wasi module") 25 | .initialize(None, None, None); 26 | vm.register_module_from_file(target.as_str(), &wasm_file)? 27 | .run_func(Some(target.as_str()), "_start", params!())?; 28 | 29 | Ok(()) 30 | } -------------------------------------------------------------------------------- /chapter-10/journal/journal_cli/src/main2.bak: -------------------------------------------------------------------------------- 1 | use std::env; 2 | use std::path::PathBuf; 3 | use wasmedge_sdk::{ 4 | config::{CommonConfigOptions, ConfigBuilder, HostRegistrationConfigOptions}, 5 | params, VmBuilder, WasmVal 6 | }; 7 | 8 | fn main() -> Result<(), Box>{ 9 | let mut args: Vec = env::args().skip(1).collect(); 10 | args.reverse(); 11 | let target = args.pop().unwrap_or("paper_search".to_string()); 12 | let filename = format!("{}.wasm", target); 13 | let wasm_file: PathBuf = ["..", "target", "wasm32-wasi", "debug", filename.as_str()].iter().collect(); 14 | //Create a config with the `wasi` option enabled 15 | let config = ConfigBuilder::new(CommonConfigOptions::default()) 16 | .with_host_registration_config(HostRegistrationConfigOptions::default().wasi(true)) 17 | .build()?; 18 | assert!(config.wasi_enabled()); 19 | 20 | // create a VM with the config 21 | let mut vm = VmBuilder::new().with_config(config).build()?; 22 | 23 | vm.wasi_module_mut() 24 | .expect("Not found wasi module") 25 | .initialize(None, None, None); 26 | vm.register_module_from_file(target.as_str(), &wasm_file)? 27 | .run_func(Some(target.as_str()), "static_search", params!(0, 1))?; 28 | Ok(()) 29 | } -------------------------------------------------------------------------------- /chapter-10/journal/journal_cli/src/main3.bak: -------------------------------------------------------------------------------- 1 | use std::env; 2 | use std::path::PathBuf; 3 | use wasmedge_sdk::{ 4 | config::{CommonConfigOptions, ConfigBuilder, HostRegistrationConfigOptions}, 5 | params, VmBuilder, WasmVal 6 | }; 7 | 8 | fn main() -> Result<(), Box>{ 9 | let mut args: Vec = env::args().skip(1).collect(); 10 | args.reverse(); 11 | let target = args.pop().unwrap_or("paper_search".to_string()); 12 | let filename = format!("{}.wasm", target); 13 | let wasm_file: PathBuf = ["..", "target", "wasm32-wasi", "debug", filename.as_str()].iter().collect(); 14 | //Create a config with the `wasi` option enabled 15 | let config = ConfigBuilder::new(CommonConfigOptions::default()) 16 | .with_host_registration_config(HostRegistrationConfigOptions::default().wasi(true)) 17 | .build()?; 18 | assert!(config.wasi_enabled()); 19 | 20 | // create a VM with the config 21 | let mut vm = VmBuilder::new().with_config(config).build()?; 22 | 23 | vm.wasi_module_mut() 24 | .expect("Not found wasi module") 25 | .initialize(None, None, None); 26 | vm.register_module_from_file(target.as_str(), &wasm_file)? 27 | .run_func(Some(target.as_str()), "_start", params!())?; 28 | Ok(()) 29 | } -------------------------------------------------------------------------------- /chapter-10/journal/paper_search/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /chapter-10/journal/paper_search/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "paper_search" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [build] 7 | target="wasm32-wasi" 8 | 9 | [target.wasm32-wasi] 10 | runner = "wasmedge" 11 | 12 | [dependencies] 13 | tokio_wasi = { version = "1.21", features = ["rt", "macros", "net", "time"]} 14 | paper_search_lib = { path = "../paper_search_lib" } -------------------------------------------------------------------------------- /chapter-10/journal/paper_search/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | use std::error::Error; 3 | use std::fmt::{self, Debug, Display, Formatter}; 4 | use std::os::raw::{c_void, c_int}; 5 | use std::mem; 6 | use std::ffi::{CStr, c_char, CString}; 7 | 8 | #[no_mangle] 9 | pub fn memory_search(term: *mut c_char) -> *mut c_char { 10 | let t = unsafe { CStr::from_ptr(term).to_bytes().to_vec() }; 11 | let mut output = t.to_vec(); 12 | let search_term: String = String::from_utf8(output).unwrap(); 13 | let res_string = search(search_term, 0, 1).unwrap(); 14 | let mut res: Vec = res_string.into_iter().nth(0).unwrap().into(); 15 | res.resize(1024, 0); 16 | unsafe { CString::from_vec_unchecked(res)}.into_raw() 17 | } 18 | 19 | #[no_mangle] 20 | pub extern fn allocate(size: usize) -> *mut c_void { 21 | let mut buffer = Vec::with_capacity(size); 22 | let pointer = buffer.as_mut_ptr(); 23 | mem::forget(buffer); 24 | 25 | pointer as *mut c_void 26 | } 27 | 28 | 29 | fn main() -> Result<(), Box> { 30 | let mut args: Vec = env::args().skip(1).collect(); 31 | args.reverse(); 32 | let term = args.pop().unwrap_or("rust".to_string()); 33 | 34 | let res: Vec = search(term, 0, 10).unwrap(); 35 | for entry in res.iter() { 36 | println!("{:?}", entry); 37 | } 38 | Ok(()) 39 | } 40 | 41 | #[no_mangle] 42 | pub fn static_search( 43 | page: isize, 44 | offset: isize, 45 | ) { 46 | 47 | let res: Vec = search("rust".to_string(), page, offset).unwrap(); 48 | for entry in res.iter() { 49 | println!("{:?}", entry); 50 | } 51 | } 52 | 53 | 54 | pub fn search( 55 | term: String, 56 | page: isize, 57 | max_results: isize, 58 | ) -> Result, Box> { 59 | let rt = tokio::runtime::Builder::new_current_thread() 60 | .enable_all() 61 | .build() 62 | .unwrap(); 63 | let feed: paper_search_lib::Feed = rt.block_on(async {paper_search_lib::search(term, page, max_results) 64 | .await}).unwrap(); 65 | let res = feed 66 | .entry 67 | .into_iter() 68 | .map(|e| format!("{} {}", e.title, e.id)) 69 | .collect::>(); 70 | return Ok::, Box>(res); 71 | } -------------------------------------------------------------------------------- /chapter-10/journal/paper_search/src/main1.bak: -------------------------------------------------------------------------------- 1 | use std::error::Error; 2 | use std::fmt::{self, Debug, Display, Formatter}; 3 | 4 | fn main() -> Result<(), Box> { 5 | let res: Vec = search("rust".to_string(), 0, 10).unwrap(); 6 | for entry in res.iter() { 7 | println!("{:?}", entry); 8 | } 9 | Ok(()) 10 | } 11 | 12 | pub fn search( 13 | term: String, 14 | page: isize, 15 | max_results: isize, 16 | ) -> Result, Box> { 17 | let rt = tokio::runtime::Builder::new_current_thread() 18 | .enable_all() 19 | .build() 20 | .unwrap(); 21 | let feed: paper_search_lib::Feed = rt.block_on(async {paper_search_lib::search(term, page, max_results) 22 | .await}).unwrap(); 23 | let res = feed 24 | .entry 25 | .into_iter() 26 | .map(|e| format!("{} {}", e.title, e.id)) 27 | .collect::>(); 28 | return Ok::, Box>(res); 29 | } -------------------------------------------------------------------------------- /chapter-10/journal/paper_search/src/main2.bak: -------------------------------------------------------------------------------- 1 | use std::env; 2 | use std::error::Error; 3 | use std::fmt::{self, Debug, Display, Formatter}; 4 | 5 | fn main() -> Result<(), Box> { 6 | let mut args: Vec = env::args().skip(1).collect(); 7 | args.reverse(); 8 | let term = args.pop().unwrap_or("rust".to_string()); 9 | 10 | let res: Vec = search(term, 0, 10).unwrap(); 11 | for entry in res.iter() { 12 | println!("{:?}", entry); 13 | } 14 | Ok(()) 15 | } 16 | 17 | pub fn search( 18 | term: String, 19 | page: isize, 20 | max_results: isize, 21 | ) -> Result, Box> { 22 | let rt = tokio::runtime::Builder::new_current_thread() 23 | .enable_all() 24 | .build() 25 | .unwrap(); 26 | let feed: paper_search_lib::Feed = rt.block_on(async {paper_search_lib::search(term, page, max_results) 27 | .await}).unwrap(); 28 | let res = feed 29 | .entry 30 | .into_iter() 31 | .map(|e| format!("{} {}", e.title, e.id)) 32 | .collect::>(); 33 | return Ok::, Box>(res); 34 | } -------------------------------------------------------------------------------- /chapter-10/journal/paper_search/src/main3.bak: -------------------------------------------------------------------------------- 1 | use std::env; 2 | use std::error::Error; 3 | use std::fmt::{self, Debug, Display, Formatter}; 4 | 5 | fn main() -> Result<(), Box> { 6 | let mut args: Vec = env::args().skip(1).collect(); 7 | args.reverse(); 8 | let term = args.pop().unwrap_or("rust".to_string()); 9 | 10 | let res: Vec = search(term, 0, 10).unwrap(); 11 | for entry in res.iter() { 12 | println!("{:?}", entry); 13 | } 14 | Ok(()) 15 | } 16 | 17 | #[no_mangle] 18 | pub fn static_search( 19 | page: isize, 20 | offset: isize, 21 | ) { 22 | 23 | let res: Vec = search("rust".to_string(), page, offset).unwrap(); 24 | for entry in res.iter() { 25 | println!("{:?}", entry); 26 | } 27 | } 28 | 29 | 30 | pub fn search( 31 | term: String, 32 | page: isize, 33 | max_results: isize, 34 | ) -> Result, Box> { 35 | let rt = tokio::runtime::Builder::new_current_thread() 36 | .enable_all() 37 | .build() 38 | .unwrap(); 39 | let feed: paper_search_lib::Feed = rt.block_on(async {paper_search_lib::search(term, page, max_results) 40 | .await}).unwrap(); 41 | let res = feed 42 | .entry 43 | .into_iter() 44 | .map(|e| format!("{} {}", e.title, e.id)) 45 | .collect::>(); 46 | return Ok::, Box>(res); 47 | } -------------------------------------------------------------------------------- /chapter-10/journal/paper_search/src/main4.bak: -------------------------------------------------------------------------------- 1 | use std::env; 2 | use std::error::Error; 3 | use std::fmt::{self, Debug, Display, Formatter}; 4 | use std::os::raw::{c_void, c_int}; 5 | use std::mem; 6 | 7 | #[no_mangle] 8 | pub extern fn allocate(size: usize) -> *mut c_void { 9 | let mut buffer = Vec::with_capacity(size); 10 | let pointer = buffer.as_mut_ptr(); 11 | mem::forget(buffer); 12 | 13 | pointer as *mut c_void 14 | } 15 | 16 | fn main() -> Result<(), Box> { 17 | let mut args: Vec = env::args().skip(1).collect(); 18 | args.reverse(); 19 | let term = args.pop().unwrap_or("rust".to_string()); 20 | 21 | let res: Vec = search(term, 0, 10).unwrap(); 22 | for entry in res.iter() { 23 | println!("{:?}", entry); 24 | } 25 | Ok(()) 26 | } 27 | 28 | #[no_mangle] 29 | pub fn static_search( 30 | page: isize, 31 | offset: isize, 32 | ) { 33 | 34 | let res: Vec = search("rust".to_string(), page, offset).unwrap(); 35 | for entry in res.iter() { 36 | println!("{:?}", entry); 37 | } 38 | } 39 | 40 | 41 | pub fn search( 42 | term: String, 43 | page: isize, 44 | max_results: isize, 45 | ) -> Result, Box> { 46 | let rt = tokio::runtime::Builder::new_current_thread() 47 | .enable_all() 48 | .build() 49 | .unwrap(); 50 | let feed: paper_search_lib::Feed = rt.block_on(async {paper_search_lib::search(term, page, max_results) 51 | .await}).unwrap(); 52 | let res = feed 53 | .entry 54 | .into_iter() 55 | .map(|e| format!("{} {}", e.title, e.id)) 56 | .collect::>(); 57 | return Ok::, Box>(res); 58 | } -------------------------------------------------------------------------------- /chapter-10/journal/paper_search_lib/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /chapter-10/journal/paper_search_lib/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "paper_search_lib" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | tokio_wasi = { version = "1.21", features = ["rt", "macros", "net", "time"]} 8 | reqwest_wasi = "0.11" 9 | serde = { version = "1.0", features = ["derive"] } 10 | serde-xml-rs = "0.6.0" -------------------------------------------------------------------------------- /chapter-10/journal/paper_search_lib/src/lib.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | use std::env; 3 | use std::error::Error; 4 | use std::fmt::{self, Debug, Display, Formatter}; 5 | 6 | #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] 7 | pub struct Feed { 8 | pub entry: Vec, 9 | } 10 | 11 | #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] 12 | pub struct Entry { 13 | pub id: String, 14 | pub updated: String, 15 | pub published: String, 16 | pub title: String, 17 | pub summary: String, 18 | pub author: Vec, 19 | } 20 | 21 | #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] 22 | pub struct Author { 23 | pub name: String, 24 | } 25 | 26 | pub async fn search(term: String, page: isize, max_results: isize) -> Result { 27 | let http_response = reqwest::get(format!( 28 | "http://export.arxiv.org/api/query?search_query=all:{}&start={}&max_results={}", 29 | term, 30 | page * max_results, 31 | max_results 32 | )) 33 | .await?; 34 | let b = http_response.text().await?; 35 | let feed: Feed = serde_xml_rs::from_str(b.as_str()).unwrap(); 36 | return Ok(feed); 37 | } -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | max_width = 76 2 | tab_spaces = 2 3 | -------------------------------------------------------------------------------- /script/build: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | import sys 5 | import glob 6 | import subprocess 7 | 8 | """ 9 | This script is used to check-compile all of the examples in this repository. 10 | It requires no arguments to run. 11 | """ 12 | 13 | BASE = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) 14 | 15 | errors = 0 16 | 17 | 18 | def find(pattern): 19 | return glob.glob(f'{BASE}/**/{pattern}', recursive=True) 20 | 21 | 22 | def run(*args): 23 | return subprocess.run( 24 | args, 25 | stdout=subprocess.DEVNULL, 26 | stderr=subprocess.DEVNULL, 27 | ).returncode 28 | 29 | 30 | for cargo in find('Cargo.toml'): 31 | rc = run( 32 | 'cargo', 33 | 'check', 34 | f'--manifest-path={cargo}', 35 | ) 36 | final_segment = os.path.dirname(cargo) 37 | 38 | if 'NO_COMPILE' in final_segment: 39 | if rc != 101: 40 | print(f'Expected {cargo} to fail to build') 41 | errors += 1 42 | else: 43 | if rc != 0: 44 | print(f'Expected {cargo} to build') 45 | errors += 1 46 | 47 | 48 | for py in find('*.py'): 49 | rc = run( 50 | 'python', 51 | '-m', 52 | 'py_compile', 53 | py, 54 | ) 55 | if rc != 0: 56 | print(f'Expected {py} to build') 57 | errors += 1 58 | 59 | for java in find('*.java'): 60 | rc = run( 61 | 'javac', 62 | java, 63 | ) 64 | if rc != 0: 65 | print(f'Expected {java} to build') 66 | errors += 1 67 | 68 | 69 | if errors == 0: 70 | print('Ok all') 71 | else: 72 | print(f'Encountered {errors} errors.') 73 | sys.exit(1) 74 | -------------------------------------------------------------------------------- /script/gen-workspace: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os.path 4 | import glob 5 | import sys 6 | 7 | os.chdir(os.path.dirname(os.path.dirname(__file__))) 8 | 9 | with open('Cargo.toml', 'w') as f: 10 | print("""# Auto generated with `./script/gen-workspace` 11 | 12 | [workspace] 13 | members = [""", file=f) 14 | 15 | chapter = 'chapter-01' 16 | 17 | for path in sorted(list(glob.glob('chapter-*/**/Cargo.toml', recursive=True))): 18 | new_chapter = path.split('/')[0] 19 | if new_chapter != chapter: 20 | print('', file=f) 21 | chapter = new_chapter 22 | 23 | dirname = os.path.dirname(path) 24 | 25 | line_start = ' ' 26 | 27 | if dirname.endswith('NO_COMPILE'): 28 | line_start = '# ' 29 | 30 | print(f'{line_start}"{dirname}",', file=f) 31 | 32 | print(']', file=f) 33 | 34 | 35 | # Note: do not add `recursive=True` to this glob call because we only want to 36 | # rewrite the crate names for listing crates that have one level of nesting. If 37 | # they have more than this they must write their own crate names 38 | for path in glob.glob('chapter-*/**/Cargo.toml'): 39 | chapter = None 40 | listing = None 41 | 42 | for component in path.split('/'): 43 | if component.startswith('chapter'): 44 | chapter = component 45 | elif component.startswith('listing'): 46 | listing = component 47 | 48 | if listing is None or chapter is None: 49 | continue 50 | 51 | listing_parts = listing.split('_') 52 | if len(listing_parts) < 2: 53 | print(f'Listing directory {chapter}/{listing} does not match expected format') 54 | sys.exit(1) 55 | 56 | name_line = f'name = "{chapter}-{listing_parts[0]}-{listing_parts[1]}"\n' 57 | 58 | seen_name_line = False 59 | 60 | new_contents = '' 61 | with open(path) as f: 62 | line = f.readline() 63 | while line: 64 | if line.startswith('name =') and not seen_name_line: 65 | seen_name_line = True 66 | new_contents += name_line 67 | else: 68 | new_contents += line 69 | 70 | line = f.readline() 71 | 72 | 73 | with open(path, 'w') as f: 74 | f.write(new_contents) 75 | 76 | -------------------------------------------------------------------------------- /script/reformat-all: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cargo fmt 4 | fd -e java -e c . -x clang-format -i {} 5 | --------------------------------------------------------------------------------