├── wtx ├── LICENSE ├── README.md ├── src │ ├── collection │ │ ├── common.rs │ │ ├── blocks_deque │ │ │ ├── metadata.rs │ │ │ └── block.rs │ │ └── expansion_ty.rs │ ├── client_api_framework │ │ ├── network │ │ │ ├── transport │ │ │ │ └── external_params.rs │ │ │ └── transport_group.rs │ │ ├── client_api_framework_error.rs │ │ ├── tests.rs │ │ ├── network.rs │ │ └── misc │ │ │ ├── from_bytes.rs │ │ │ └── request_limit.rs │ ├── database │ │ ├── client │ │ │ ├── mysql │ │ │ │ ├── tys.rs │ │ │ │ ├── protocol │ │ │ │ │ ├── decode_wrapper_protocol.rs │ │ │ │ │ ├── ping_req.rs │ │ │ │ │ ├── auth_switch_req.rs │ │ │ │ │ ├── encode_wrapper_protocol.rs │ │ │ │ │ ├── query_req.rs │ │ │ │ │ ├── prepare_req.rs │ │ │ │ │ ├── stmt_close_req.rs │ │ │ │ │ ├── lenenc_content.rs │ │ │ │ │ ├── prepare_res.rs │ │ │ │ │ ├── ok_res.rs │ │ │ │ │ ├── initial_req.rs │ │ │ │ │ └── packet_req.rs │ │ │ │ ├── flag.rs │ │ │ │ ├── encode_wrapper.rs │ │ │ │ ├── command.rs │ │ │ │ ├── ty_params.rs │ │ │ │ ├── mysql_column_info.rs │ │ │ │ └── mysql_error.rs │ │ │ ├── rdbms │ │ │ │ ├── column_info.rs │ │ │ │ ├── statements_misc.rs │ │ │ │ └── common_record.rs │ │ │ └── postgres │ │ │ │ ├── tys.rs │ │ │ │ ├── encode_wrapper.rs │ │ │ │ ├── tys │ │ │ │ ├── arguments.rs │ │ │ │ └── uuid.rs │ │ │ │ └── postgres_column_info.rs │ │ ├── schema_manager │ │ │ ├── integration_tests │ │ │ │ ├── db.rs │ │ │ │ ├── schema │ │ │ │ │ └── without_schema.rs │ │ │ │ └── backend.rs │ │ │ ├── migration.rs │ │ │ ├── migration │ │ │ │ ├── migration_common.rs │ │ │ │ ├── migration_group_common.rs │ │ │ │ └── db_migration_group.rs │ │ │ ├── macros.rs │ │ │ ├── repeatability.rs │ │ │ ├── commands │ │ │ │ ├── clear.rs │ │ │ │ └── multi.rs │ │ │ ├── migration_status.rs │ │ │ ├── fixed_sql_commands.rs │ │ │ └── schema_manager_error.rs │ │ ├── json.rs │ │ ├── client.rs │ │ ├── database_ty.rs │ │ ├── value_ident.rs │ │ ├── database_error.rs │ │ └── records.rs │ ├── http2 │ │ ├── tests.rs │ │ ├── writer_data.rs │ │ ├── initial_server_stream_remote.rs │ │ ├── reader_data.rs │ │ ├── continuation_frame.rs │ │ └── stream_state.rs │ ├── de │ │ ├── protocol │ │ │ ├── verbatim.rs │ │ │ ├── graph_ql.rs │ │ │ ├── json_rpc.rs │ │ │ ├── json_rpc │ │ │ │ ├── json_rpc_notification_params.rs │ │ │ │ ├── json_rpc_notification.rs │ │ │ │ └── json_rpc_decoder_error.rs │ │ │ ├── misc.rs │ │ │ └── graph_ql │ │ │ │ └── graph_ql_error.rs │ │ ├── dec_error.rs │ │ ├── format │ │ │ ├── hex.rs │ │ │ ├── urlencoded.rs │ │ │ ├── quick_protobuf.rs │ │ │ ├── decode_wrapper.rs │ │ │ ├── encode_wrapper.rs │ │ │ ├── borsh.rs │ │ │ └── de.rs │ │ ├── protocol.rs │ │ └── format.rs │ ├── http │ │ ├── client_pool │ │ │ ├── client_pool_resource.rs │ │ │ ├── client_pool_rm.rs │ │ │ └── integration_tests.rs │ │ ├── cookie │ │ │ ├── cookie_error.rs │ │ │ └── same_site.rs │ │ ├── protocol.rs │ │ ├── server_framework │ │ │ ├── conn_aux.rs │ │ │ ├── stream_aux.rs │ │ │ ├── macros.rs │ │ │ ├── path_params.rs │ │ │ ├── route_match.rs │ │ │ ├── methods.rs │ │ │ ├── server_framework_error.rs │ │ │ ├── middleware.rs │ │ │ ├── verbatim_params.rs │ │ │ └── res_finalizer.rs │ │ ├── version.rs │ │ ├── optioned_server.rs │ │ ├── misc.rs │ │ ├── session │ │ │ ├── session_error.rs │ │ │ └── session_state.rs │ │ ├── session.rs │ │ ├── cookie.rs │ │ ├── http_error.rs │ │ ├── generic_response.rs │ │ ├── generic_header.rs │ │ ├── response.rs │ │ └── request.rs │ ├── bench.rs │ ├── executor.rs │ ├── misc │ │ ├── enum_var_strings.rs │ │ ├── hints.rs │ │ ├── env_vars.rs │ │ ├── span.rs │ │ ├── utf8_errors.rs │ │ ├── poll_once.rs │ │ └── connection_state.rs │ ├── web_socket │ │ ├── is_in_continuation_frame.rs │ │ ├── web_socket_parts.rs │ │ ├── compression │ │ │ ├── deflate_config.rs │ │ │ ├── window_bits.rs │ │ │ └── compression_level.rs │ │ ├── op_code.rs │ │ └── web_socket_error.rs │ ├── client_api_framework.rs │ ├── rng │ │ ├── crypto_rng.rs │ │ ├── fastrand.rs │ │ ├── from_rng.rs │ │ └── seedable_rng.rs │ ├── calendar │ │ ├── macros.rs │ │ ├── time_zone.rs │ │ ├── time_zone │ │ │ ├── local.rs │ │ │ └── utc.rs │ │ ├── tracing_tree_timer.rs │ │ ├── ce_days.rs │ │ ├── day_of_year.rs │ │ ├── format │ │ │ └── push.rs │ │ └── misc.rs │ ├── executor │ │ └── curr_thread_waker.rs │ ├── stream │ │ ├── embassy_net.rs │ │ ├── async_net.rs │ │ ├── stream_with_tls.rs │ │ └── stream_writer.rs │ ├── sync │ │ ├── fence.rs │ │ ├── ref_counter.rs │ │ ├── cache_padded.rs │ │ └── sync_mutex │ │ │ └── no_std.rs │ ├── pool.rs │ ├── sync.rs │ ├── de.rs │ ├── collection.rs │ ├── tests.rs │ └── grpc.rs └── tests │ └── embed-migrations.rs ├── wtx-macros ├── LICENSE ├── README.md ├── src │ ├── client_api_framework │ │ ├── api │ │ │ └── mode.rs │ │ ├── pkg │ │ │ ├── enum_struct_or_type.rs │ │ │ ├── sir.rs │ │ │ ├── data_format_elems.rs │ │ │ ├── keywords.rs │ │ │ ├── fir │ │ │ │ ├── fir_res_item_values.rs │ │ │ │ ├── fir_req_item_values.rs │ │ │ │ ├── fir_params_items_values.rs │ │ │ │ ├── fir_after_sending_item_values.rs │ │ │ │ ├── fir_before_sending_item_values.rs │ │ │ │ ├── fir_custom_field_field_attr.rs │ │ │ │ ├── fir_aux_field_attr.rs │ │ │ │ └── fir_custom_field_attr.rs │ │ │ ├── fir.rs │ │ │ └── sir │ │ │ │ └── sir_pkg_attr.rs │ │ ├── owned_or_ref.rs │ │ ├── item_with_attr_span.rs │ │ └── contained_attrs.rs │ └── client_api_framework.rs └── Cargo.toml ├── wtx-ui ├── LICENSE ├── src │ └── main.rs └── README.md ├── wtx-docs ├── src │ ├── README.md │ ├── executor │ │ └── README.md │ ├── secrets │ │ └── README.md │ ├── ui-tools │ │ └── README.md │ ├── http-client-pool │ │ └── README.md │ ├── calendar │ │ └── README.md │ ├── environment-variables │ │ └── README.md │ ├── SUMMARY.md │ ├── web-socket-over-http2 │ │ └── README.md │ └── grpc │ │ └── README.md └── book.toml ├── wtx-instances ├── src │ ├── grpc_bindings.rs │ ├── grpc.proto │ └── bin │ │ └── autobahn-client.rs ├── README.md ├── generic-examples │ ├── calendar.rs │ ├── executor.rs │ ├── http-client-pool.rs │ ├── secrets.rs │ ├── environment-variables.rs │ └── grpc-client.rs ├── database-examples │ ├── database-client-mysql.rs │ ├── database-client-postgres-batch.rs │ └── database-client-postgres.rs ├── http-server-framework-examples │ ├── http-server-framework-cors.rs │ └── http-server-framework-redirect.rs ├── build.rs └── http2-examples │ └── http2-client.rs ├── .scripts ├── podman-rm.sh ├── internal-tests5.sh ├── internal-tests4.sh ├── loom.sh ├── autobahn │ ├── fuzzingserver.json │ ├── fuzzingclient.json │ ├── fuzzingserver-min.json │ └── fuzzingclient-min.json ├── profile.sh ├── internal-tests.sh ├── common.sh ├── integration-tests.sh ├── internal-tests3.sh ├── integration-tests-mysql.sh ├── h2load.sh ├── curl.sh ├── podman-start.sh ├── autobahn-fuzzingserver.sh ├── autobahn-fuzzingclient.sh ├── autobahn-fuzzingserver-concurrent.sh ├── internal-tests2.sh └── internal-tests0.sh ├── .test-utils ├── migrations │ ├── 2__more_stuff │ │ ├── 3__ultra_fancy_stuff │ │ │ ├── 3__ultra_fancy_stuff_out.sql │ │ │ ├── 3__ultra_fancy_stuff.toml │ │ │ └── 3__ultra_fancy_stuff_in.sql │ │ ├── 2__insert_stuff │ │ │ ├── 2__insert_stuff_out.sql │ │ │ └── 2__insert_stuff_in.sql │ │ └── 1__create_stuff.sql │ └── 1__initial │ │ ├── 1__create_author.sql │ │ ├── 2__create_post.sql │ │ └── 3__insert_author.sql ├── migrations.toml └── my.cnf ├── .github ├── PULL_REQUEST_TEMPLATE.md ├── dependabot.yml └── workflows │ └── bencher.yaml ├── rust-toolchain ├── wtx-macros-tests ├── tests │ ├── expand │ │ ├── table.rs │ │ ├── table.stdout │ │ └── from_vars.rs │ ├── fail │ │ ├── bad_aux_data.stderr │ │ ├── bad_res.stderr │ │ ├── bad_req.stderr │ │ ├── unknown_data_format.rs │ │ ├── bad_params.stderr │ │ ├── mandatory_outer_attrs_are_not_present.rs │ │ ├── bad_req.rs │ │ ├── bad_res.rs │ │ ├── incorrect_json_rpc_data_format.rs │ │ ├── unknown_transport.rs │ │ ├── responses_can_not_have_type_params.rs │ │ ├── duplicated_global_pkg_attr.rs │ │ ├── absent_field_in_unnamed_struct.stderr │ │ ├── responses_can_not_have_type_params.stderr │ │ ├── absent_field_in_unnamed_struct.rs │ │ ├── absent_req_or_res.rs │ │ ├── bad_aux.rs │ │ ├── duplicated_global_pkg_attr.stderr │ │ ├── unknown_transport.stderr │ │ ├── bad_params.rs │ │ ├── bad_aux.stderr │ │ ├── bad_after_sending.rs │ │ ├── bad_aux_data.rs │ │ ├── bad_before_sending.rs │ │ ├── bad_before_sending.stderr │ │ ├── bad_after_sending.stderr │ │ ├── unknown_data_format.stderr │ │ ├── bad_field.stderr │ │ ├── bad_field.rs │ │ ├── incorrect_json_rpc_data_format.stderr │ │ ├── mandatory_outer_attrs_are_not_present.stderr │ │ ├── no_enum_struct_or_type.rs │ │ ├── no_enum_struct_or_type.stderr │ │ ├── absent_req_or_res.stderr │ │ ├── duplicated_local_pkg_attr.stderr │ │ └── duplicated_local_pkg_attr.rs │ └── pass │ │ ├── from_records.rs │ │ ├── data_with_params.rs │ │ ├── pkgs_aux_bounds.rs │ │ ├── df_builder_with_req_lf.rs │ │ └── mutable_references.rs └── Cargo.toml ├── .editorconfig ├── rustfmt.toml ├── wtx-fuzz ├── date_time.rs ├── Cargo.toml └── web_socket.rs ├── .gitignore ├── SECURITY.md ├── Cargo.toml ├── clippy.toml └── .certs ├── root-ca.crt └── cert.pem /wtx/LICENSE: -------------------------------------------------------------------------------- 1 | ../LICENSE -------------------------------------------------------------------------------- /wtx-macros/LICENSE: -------------------------------------------------------------------------------- 1 | ../LICENSE -------------------------------------------------------------------------------- /wtx-ui/LICENSE: -------------------------------------------------------------------------------- 1 | ../LICENSE -------------------------------------------------------------------------------- /wtx/README.md: -------------------------------------------------------------------------------- 1 | ../README.md -------------------------------------------------------------------------------- /wtx/src/collection/common.rs: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /wtx-macros/README.md: -------------------------------------------------------------------------------- 1 | ../README.md -------------------------------------------------------------------------------- /wtx-docs/src/README.md: -------------------------------------------------------------------------------- 1 | ../../README.md -------------------------------------------------------------------------------- /wtx/src/client_api_framework/network/transport/external_params.rs: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /wtx-instances/src/grpc_bindings.rs: -------------------------------------------------------------------------------- 1 | include!(concat!(env!("OUT_DIR"), "/protos/mod.rs")); 2 | -------------------------------------------------------------------------------- /wtx/src/database/client/mysql/tys.rs: -------------------------------------------------------------------------------- 1 | mod calendar; 2 | mod collection; 3 | mod primitives; 4 | -------------------------------------------------------------------------------- /.scripts/podman-rm.sh: -------------------------------------------------------------------------------- 1 | podman container rm -fi wtx_mysql 2 | podman container rm -fi wtx_postgres_scram 3 | -------------------------------------------------------------------------------- /wtx-docs/book.toml: -------------------------------------------------------------------------------- 1 | [book] 2 | authors = ["Caio"] 3 | language = "en" 4 | src = "src" 5 | title = "WTX" 6 | -------------------------------------------------------------------------------- /.test-utils/migrations/2__more_stuff/3__ultra_fancy_stuff/3__ultra_fancy_stuff_out.sql: -------------------------------------------------------------------------------- 1 | DROP PROCEDURE something(); -------------------------------------------------------------------------------- /wtx/src/database/schema_manager/integration_tests/db.rs: -------------------------------------------------------------------------------- 1 | pub(crate) mod mysql; 2 | pub(crate) mod postgres; 3 | -------------------------------------------------------------------------------- /.test-utils/migrations/2__more_stuff/2__insert_stuff/2__insert_stuff_out.sql: -------------------------------------------------------------------------------- 1 | DELETE FROM apple; 2 | DELETE FROM coffee; -------------------------------------------------------------------------------- /.scripts/internal-tests5.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -euxo pipefail 4 | 5 | pushd wtx-macros-tests 6 | cargo run -------------------------------------------------------------------------------- /.test-utils/migrations.toml: -------------------------------------------------------------------------------- 1 | migration_groups = [ 2 | "migrations/1__initial", 3 | "migrations/2__more_stuff" 4 | ] -------------------------------------------------------------------------------- /wtx-macros/src/client_api_framework/api/mode.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug)] 2 | pub(crate) enum Mode { 3 | Auto, 4 | Manual, 5 | } 6 | -------------------------------------------------------------------------------- /wtx/src/http2/tests.rs: -------------------------------------------------------------------------------- 1 | mod connections; 2 | #[cfg(all(feature = "_integration-tests", feature = "serde_json"))] 3 | mod hpack; 4 | -------------------------------------------------------------------------------- /.test-utils/migrations/2__more_stuff/3__ultra_fancy_stuff/3__ultra_fancy_stuff.toml: -------------------------------------------------------------------------------- 1 | dbs = ["postgres"] 2 | repeatability = "always" 3 | -------------------------------------------------------------------------------- /.test-utils/my.cnf: -------------------------------------------------------------------------------- 1 | [mysqld] 2 | ssl-ca=/var/lib/mysql/root-ca.crt 3 | ssl-cert=/var/lib/mysql/cert.pem 4 | ssl-key=/var/lib/mysql/key.pem -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Please include at least a minimal description. If the PR is large, try splitting it into other smaller PRs. 2 | -------------------------------------------------------------------------------- /.test-utils/migrations/2__more_stuff/3__ultra_fancy_stuff/3__ultra_fancy_stuff_in.sql: -------------------------------------------------------------------------------- 1 | CREATE OR REPLACE PROCEDURE something() LANGUAGE SQL AS $$ $$ -------------------------------------------------------------------------------- /rust-toolchain: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "nightly-2025-10-31" 3 | components = ["clippy", "miri", "rustfmt", "rust-src"] 4 | profile = "minimal" 5 | -------------------------------------------------------------------------------- /wtx-macros-tests/tests/expand/table.rs: -------------------------------------------------------------------------------- 1 | #[derive(wtx_macros::Table)] 2 | pub struct Foo { 3 | bar: String, 4 | baz: String, 5 | } 6 | 7 | fn main() {} -------------------------------------------------------------------------------- /wtx/src/de/protocol/verbatim.rs: -------------------------------------------------------------------------------- 1 | mod verbatim_decoder; 2 | mod verbatim_encoder; 3 | 4 | pub use verbatim_decoder::*; 5 | pub use verbatim_encoder::*; 6 | -------------------------------------------------------------------------------- /wtx/src/database/client/rdbms/column_info.rs: -------------------------------------------------------------------------------- 1 | pub(crate) trait ColumnInfo { 2 | type Ty; 3 | 4 | fn name(&self) -> &str; 5 | 6 | fn ty(&self) -> &Self::Ty; 7 | } 8 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | indent_size = 2 7 | indent_style = space 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true -------------------------------------------------------------------------------- /.scripts/internal-tests4.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -euxo pipefail 4 | 5 | cargo fuzz run --features libfuzzer-sys/link_libfuzzer --fuzz-dir wtx-fuzz web-socket -- -max_total_time=120 -------------------------------------------------------------------------------- /.scripts/loom.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | cd wtx 4 | LOOM_MAX_PREEMPTIONS=2 \ 5 | LOOM_MAX_BRANCHES=1000000 \ 6 | RUSTFLAGS="--cfg loom" \ 7 | cargo test --features loom --profile deploy loom_tests -------------------------------------------------------------------------------- /.test-utils/migrations/2__more_stuff/2__insert_stuff/2__insert_stuff_in.sql: -------------------------------------------------------------------------------- 1 | INSERT INTO apple(id, weight) VALUES 2 | ('1',12), 3 | ('2',21); 4 | 5 | INSERT INTO coffee(id) VALUES 6 | ('1'), 7 | ('2'); -------------------------------------------------------------------------------- /wtx/src/collection/blocks_deque/metadata.rs: -------------------------------------------------------------------------------- 1 | #[derive(Clone, Copy, Debug)] 2 | pub(crate) struct Metadata { 3 | pub(crate) len: usize, 4 | pub(crate) misc: M, 5 | pub(crate) offset: usize, 6 | } 7 | -------------------------------------------------------------------------------- /.scripts/autobahn/fuzzingserver.json: -------------------------------------------------------------------------------- 1 | { 2 | "cases": ["*"], 3 | "exclude-agent-cases": {}, 4 | "exclude-cases": [], 5 | "outdir": "/autobahn/reports/fuzzingserver", 6 | "url": "ws://127.0.0.1:9080" 7 | } -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | edition = "2024" 2 | imports_granularity = "Crate" 3 | newline_style = "Unix" 4 | reorder_imports = true 5 | tab_spaces = 2 6 | use_field_init_shorthand = true 7 | use_small_heuristics = "Max" 8 | -------------------------------------------------------------------------------- /wtx/src/de/protocol/graph_ql.rs: -------------------------------------------------------------------------------- 1 | mod graph_ql_decoder; 2 | mod graph_ql_encoder; 3 | mod graph_ql_error; 4 | 5 | pub use graph_ql_decoder::*; 6 | pub use graph_ql_encoder::*; 7 | pub use graph_ql_error::*; 8 | -------------------------------------------------------------------------------- /wtx-macros/src/client_api_framework.rs: -------------------------------------------------------------------------------- 1 | pub(crate) mod api; 2 | pub(crate) mod contained_attrs; 3 | pub(crate) mod item_with_attr_span; 4 | pub(crate) mod owned_or_ref; 5 | pub(crate) mod pkg; 6 | pub(crate) mod transport_group; 7 | -------------------------------------------------------------------------------- /wtx/src/http/client_pool/client_pool_resource.rs: -------------------------------------------------------------------------------- 1 | /// Client pool resource 2 | #[derive(Debug)] 3 | pub struct ClientPoolResource { 4 | /// Auxiliary structure 5 | pub aux: AUX, 6 | /// Client 7 | pub client: C, 8 | } 9 | -------------------------------------------------------------------------------- /wtx/src/http/cookie/cookie_error.rs: -------------------------------------------------------------------------------- 1 | /// Cookie error 2 | #[derive(Debug)] 3 | pub enum CookieError { 4 | /// Cookie does not contain a `=` separator 5 | IrregularCookie, 6 | /// Cookie has an empty name 7 | MissingName, 8 | } 9 | -------------------------------------------------------------------------------- /wtx-fuzz/date_time.rs: -------------------------------------------------------------------------------- 1 | //! DateTime 2 | 3 | #![no_main] 4 | 5 | use wtx::calendar::DateTime; 6 | 7 | libfuzzer_sys::fuzz_target!(|(value, fmt): (Vec, Vec)| { 8 | let _rslt = DateTime::parse(&value, &value); 9 | }); 10 | -------------------------------------------------------------------------------- /wtx-macros-tests/tests/fail/bad_aux_data.stderr: -------------------------------------------------------------------------------- 1 | error: This method must be named `foo_data` 2 | --> tests/fail/bad_aux_data.rs:6:8 3 | | 4 | 6 | fn fdsfqw() {} 5 | | ^^^^^^ 6 | 7 | error: aborting due to 1 previous error 8 | 9 | -------------------------------------------------------------------------------- /wtx-macros-tests/tests/fail/bad_res.stderr: -------------------------------------------------------------------------------- 1 | error: Response data must end with the `Res` suffix. 2 | --> tests/fail/bad_res.rs:8:10 3 | | 4 | 8 | struct ResDSA; 5 | | ^^^^^^ 6 | 7 | error: aborting due to 1 previous error 8 | 9 | -------------------------------------------------------------------------------- /wtx-macros-tests/tests/fail/bad_req.stderr: -------------------------------------------------------------------------------- 1 | error: Request data must end with the `Req` suffix. 2 | --> tests/fail/bad_req.rs:5:14 3 | | 4 | 5 | pub struct Rfdsqw; 5 | | ^^^^^^ 6 | 7 | error: aborting due to 1 previous error 8 | 9 | -------------------------------------------------------------------------------- /wtx-macros-tests/tests/fail/unknown_data_format.rs: -------------------------------------------------------------------------------- 1 | #[wtx_macros::pkg(data_format(fdsdfs), id(Foo))] 2 | mod pkg { 3 | #[pkg::req_data] 4 | struct Req; 5 | 6 | #[pkg::res_data] 7 | struct Res; 8 | } 9 | 10 | fn main() { 11 | } 12 | -------------------------------------------------------------------------------- /wtx-macros-tests/tests/fail/bad_params.stderr: -------------------------------------------------------------------------------- 1 | error: Parameters must end with the `Params` suffix. 2 | --> tests/fail/bad_params.rs:5:14 3 | | 4 | 5 | pub struct Rfewr; 5 | | ^^^^^ 6 | 7 | error: aborting due to 1 previous error 8 | 9 | -------------------------------------------------------------------------------- /wtx/src/http/protocol.rs: -------------------------------------------------------------------------------- 1 | create_enum! { 2 | /// Specifies a tunneling protocol 3 | #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] 4 | pub enum Protocol { 5 | /// WebSocket 6 | WebSocket = (0, "websocket") 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /wtx-macros-tests/tests/fail/mandatory_outer_attrs_are_not_present.rs: -------------------------------------------------------------------------------- 1 | #[wtx_macros::pkg(data_format(), id(Foo))] 2 | mod pkg { 3 | #[pkg::req_data] 4 | struct Req; 5 | 6 | #[pkg::res_data] 7 | struct Res; 8 | } 9 | 10 | fn main() { 11 | } 12 | -------------------------------------------------------------------------------- /wtx-macros/src/client_api_framework/pkg/enum_struct_or_type.rs: -------------------------------------------------------------------------------- 1 | use syn::{ItemStruct, ItemType}; 2 | 3 | #[derive(Clone, Copy, Debug)] 4 | pub(crate) enum EnumStructOrType<'any> { 5 | Enum, 6 | Struct(&'any ItemStruct), 7 | Type(&'any ItemType), 8 | } 9 | -------------------------------------------------------------------------------- /wtx-macros-tests/tests/fail/bad_req.rs: -------------------------------------------------------------------------------- 1 | #[wtx_macros::pkg(data_format(json), id(FooId))] 2 | mod pkg { 3 | #[derive(Debug)] 4 | #[pkg::req_data] 5 | pub struct Rfdsqw; 6 | 7 | #[pkg::res_data] 8 | struct Res; 9 | } 10 | 11 | fn main() { 12 | } 13 | -------------------------------------------------------------------------------- /wtx-macros-tests/tests/fail/bad_res.rs: -------------------------------------------------------------------------------- 1 | #[wtx_macros::pkg(data_format(json), id(FooId))] 2 | mod pkg { 3 | #[derive(Debug)] 4 | #[pkg::req_data] 5 | pub struct Req; 6 | 7 | #[pkg::res_data] 8 | struct ResDSA; 9 | } 10 | 11 | fn main() { 12 | } 13 | -------------------------------------------------------------------------------- /wtx-macros-tests/tests/fail/incorrect_json_rpc_data_format.rs: -------------------------------------------------------------------------------- 1 | #[wtx_macros::pkg(data_format(json_rpc(Bar)), id(Foo))] 2 | mod pkg { 3 | #[pkg::req_data] 4 | struct Req; 5 | 6 | #[pkg::res_data] 7 | struct Res; 8 | } 9 | 10 | fn main() { 11 | } 12 | -------------------------------------------------------------------------------- /wtx-macros-tests/tests/fail/unknown_transport.rs: -------------------------------------------------------------------------------- 1 | #[wtx_macros::pkg(data_format(json), id(FooId), transport(dasdasd))] 2 | mod pkg { 3 | #[pkg::req_data] 4 | struct Req; 5 | 6 | #[pkg::res_data] 7 | struct Res; 8 | } 9 | 10 | fn main() { 11 | } 12 | -------------------------------------------------------------------------------- /wtx-macros-tests/tests/fail/responses_can_not_have_type_params.rs: -------------------------------------------------------------------------------- 1 | #[wtx_macros::pkg(data_format(json), id(FooId))] 2 | mod pkg { 3 | #[pkg::req_data] 4 | struct Req; 5 | 6 | #[pkg::res_data] 7 | struct Res(T); 8 | } 9 | 10 | fn main() { 11 | } 12 | -------------------------------------------------------------------------------- /wtx/src/bench.rs: -------------------------------------------------------------------------------- 1 | use crate::collection::Vector; 2 | 3 | pub(crate) fn _data(len: usize) -> Vector { 4 | Vector::from_iterator((0..len).map(|el| { 5 | let n = el % usize::from(u8::MAX); 6 | n.try_into().unwrap() 7 | })) 8 | .unwrap() 9 | } 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .scripts/autobahn/reports 2 | .vscode 3 | **/*.rs.bk 4 | **/curl 5 | **/hpack-test-case 6 | **/profile.json 7 | **/rustc-ice-*.txt 8 | **/target 9 | boringssl 10 | callgrind* 11 | mdbook-target 12 | wtx-docs/book 13 | wtx-fuzz/artifacts 14 | wtx-fuzz/corpus -------------------------------------------------------------------------------- /wtx/src/http2/writer_data.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug)] 2 | pub(crate) struct WriterData { 3 | pub(crate) stream_writer: SW, 4 | } 5 | 6 | impl WriterData { 7 | pub(crate) fn new(stream_writer: SW) -> Self { 8 | Self { stream_writer } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /wtx-macros-tests/tests/pass/from_records.rs: -------------------------------------------------------------------------------- 1 | use wtx::database::client::postgres::Postgres; 2 | 3 | #[derive(wtx_macros::FromRecords)] 4 | #[from_records(Postgres)] 5 | pub struct Foo { 6 | pub bar: i32, 7 | pub baz: i64, 8 | } 9 | 10 | fn main() {} 11 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security policy 2 | 3 | You can report security vulnerabilities with as much information as possible through our [security page](https://github.com/c410-f3r/wtx/security). Security advisories will be available at . 4 | -------------------------------------------------------------------------------- /wtx-macros-tests/tests/fail/duplicated_global_pkg_attr.rs: -------------------------------------------------------------------------------- 1 | #[wtx_macros::pkg(data_format(json), id(FooId))] 2 | mod pkg { 3 | #[derive(Debug)] 4 | #[pkg::req_data] 5 | pub struct Req; 6 | 7 | #[pkg::req_data] 8 | struct Res; 9 | } 10 | 11 | fn main() { 12 | } 13 | -------------------------------------------------------------------------------- /wtx/src/executor.rs: -------------------------------------------------------------------------------- 1 | //! Simple dependency-free runtime intended for tests, toy programs and demonstrations, 2 | 3 | #![allow(clippy::disallowed_types, reason = "traits require the `Arc` from std")] 4 | 5 | mod curr_thread_waker; 6 | mod runtime; 7 | 8 | pub use runtime::Runtime; 9 | -------------------------------------------------------------------------------- /wtx/src/http/server_framework/conn_aux.rs: -------------------------------------------------------------------------------- 1 | /// Auxiliary structure for connections 2 | pub trait ConnAux: Sized { 3 | /// Initialization 4 | type Init; 5 | 6 | /// Creates a new instance with [`ConnAux::Init`]. 7 | fn conn_aux(init: Self::Init) -> crate::Result; 8 | } 9 | -------------------------------------------------------------------------------- /wtx/src/misc/enum_var_strings.rs: -------------------------------------------------------------------------------- 1 | /// Enum Variant Strings 2 | #[derive(Debug)] 3 | pub struct EnumVarStrings { 4 | /// Custom 5 | pub custom: [&'static str; N], 6 | /// Identifier 7 | pub ident: &'static str, 8 | /// Number 9 | pub number: &'static str, 10 | } 11 | -------------------------------------------------------------------------------- /.scripts/autobahn/fuzzingclient.json: -------------------------------------------------------------------------------- 1 | { 2 | "cases": ["*"], 3 | "exclude-agent-cases": {}, 4 | "exclude-cases": [], 5 | "outdir": "/autobahn/reports/fuzzingclient", 6 | "servers": [ 7 | { 8 | "agent": "wtx", 9 | "url": "ws://127.0.0.1:9070" 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /.scripts/profile.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # sudo setcap 'cap_perfmon+ep' `which samply` 4 | # sudo sysctl kernel.perf_event_mlock_kb=2048 5 | 6 | CMD="cargo test --profile profiling --no-run" 7 | 8 | BINARY=$($CMD -v 2>&1 | grep -o "\`.*\`") 9 | 10 | samply record ${BINARY:1:-1} 11 | -------------------------------------------------------------------------------- /wtx-macros/src/client_api_framework/pkg/sir.rs: -------------------------------------------------------------------------------- 1 | //! Second Intermediate Representation (SIR) 2 | //! 3 | //! Uses one or more FIR structures to modify, validate and construct final elements. 4 | 5 | pub(crate) mod sir_aux_item_values; 6 | pub(crate) mod sir_final_values; 7 | pub(crate) mod sir_pkg_attr; 8 | -------------------------------------------------------------------------------- /wtx/src/database/json.rs: -------------------------------------------------------------------------------- 1 | /// Wrapper around JSON values 2 | #[derive(Debug, PartialEq)] 3 | #[cfg_attr(feature = "serde_json", derive(serde::Deserialize, serde::Serialize))] 4 | #[cfg_attr(feature = "serde_json", serde(transparent))] 5 | pub struct Json( 6 | /// Value 7 | pub T, 8 | ); 9 | -------------------------------------------------------------------------------- /.test-utils/migrations/1__initial/1__create_author.sql: -------------------------------------------------------------------------------- 1 | -- wtx IN 2 | 3 | CREATE TABLE author ( 4 | id INT NOT NULL PRIMARY KEY, 5 | first_name VARCHAR(50) NOT NULL, 6 | last_name VARCHAR(50) NOT NULL, 7 | email VARCHAR(100) NOT NULL 8 | ); 9 | 10 | -- wtx OUT 11 | 12 | DROP TABLE author; 13 | -------------------------------------------------------------------------------- /wtx-instances/README.md: -------------------------------------------------------------------------------- 1 | # WTX instances 2 | 3 | Groups user examples as well as compliance binaries. 4 | 5 | Note that this crate (`wtx-instances`) provides common auxiliary functionalities that are not meant for public usage. For example, you should generate or obtain your own valid certificates for servers. -------------------------------------------------------------------------------- /wtx-macros-tests/tests/fail/absent_field_in_unnamed_struct.stderr: -------------------------------------------------------------------------------- 1 | error: Unnamed structures must have a `#[pkg::field]` attribute on each field. 2 | --> tests/fail/absent_field_in_unnamed_struct.rs:7:10 3 | | 4 | 7 | struct Req( 5 | | ^^^ 6 | 7 | error: aborting due to 1 previous error 8 | 9 | -------------------------------------------------------------------------------- /wtx/src/web_socket/is_in_continuation_frame.rs: -------------------------------------------------------------------------------- 1 | use crate::{misc::IncompleteUtf8Char, web_socket::OpCode}; 2 | 3 | #[derive(Debug)] 4 | pub(crate) struct IsInContinuationFrame { 5 | pub(crate) iuc: Option, 6 | pub(crate) op_code: OpCode, 7 | pub(crate) should_decompress: bool, 8 | } 9 | -------------------------------------------------------------------------------- /wtx-macros-tests/tests/fail/responses_can_not_have_type_params.stderr: -------------------------------------------------------------------------------- 1 | error: Responses can have at most one lifetime. Types aren't supported 2 | --> tests/fail/responses_can_not_have_type_params.rs:7:10 3 | | 4 | 7 | struct Res(T); 5 | | ^^^ 6 | 7 | error: aborting due to 1 previous error 8 | 9 | -------------------------------------------------------------------------------- /.test-utils/migrations/2__more_stuff/1__create_stuff.sql: -------------------------------------------------------------------------------- 1 | -- wtx IN 2 | 3 | CREATE TABLE apple ( 4 | id INT NOT NULL PRIMARY KEY, 5 | weight INT NOT NULL 6 | ); 7 | 8 | CREATE TABLE coffee ( 9 | id INT NOT NULL PRIMARY KEY 10 | ); 11 | 12 | -- wtx OUT 13 | 14 | DROP TABLE coffee; 15 | DROP TABLE apple; -------------------------------------------------------------------------------- /wtx-macros-tests/tests/fail/absent_field_in_unnamed_struct.rs: -------------------------------------------------------------------------------- 1 | #[wtx_macros::pkg(data_format(json), id(FooId))] 2 | mod pkg { 3 | #[pkg::aux] 4 | impl Foo {} 5 | 6 | #[pkg::req_data] 7 | struct Req( 8 | i32 9 | ); 10 | 11 | #[pkg::res_data] 12 | struct Res; 13 | } 14 | 15 | fn main() { 16 | } 17 | -------------------------------------------------------------------------------- /wtx/src/client_api_framework/client_api_framework_error.rs: -------------------------------------------------------------------------------- 1 | /// Client API Framework Error 2 | #[derive(Debug)] 3 | pub enum ClientApiFrameworkError { 4 | /// The server closed the connection 5 | ClosedWsConnection, 6 | /// No stored test response to return a result from a request 7 | TestTransportNoResponse, 8 | } 9 | -------------------------------------------------------------------------------- /wtx/src/collection/blocks_deque/block.rs: -------------------------------------------------------------------------------- 1 | use core::ops::Range; 2 | 3 | /// A block that composes `BlocksDeque`. 4 | #[derive(Debug, PartialEq)] 5 | pub struct Block { 6 | /// Opaque data 7 | pub data: D, 8 | /// Miscellaneous 9 | pub misc: M, 10 | /// Range 11 | pub range: Range, 12 | } 13 | -------------------------------------------------------------------------------- /wtx/src/web_socket/web_socket_parts.rs: -------------------------------------------------------------------------------- 1 | // Common elements shared between pure WebSocket structures. Tunneling protocols should use 2 | // the functions provided in `web_socket_reader` and `web_socket_writer`. 3 | 4 | pub(crate) mod web_socket_generic; 5 | pub(crate) mod web_socket_mut; 6 | pub(crate) mod web_socket_owned; 7 | -------------------------------------------------------------------------------- /.scripts/internal-tests.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | $(dirname "$0")/internal-tests0.sh \ 4 | && $(dirname "$0")/internal-tests1.sh \ 5 | && $(dirname "$0")/internal-tests2.sh \ 6 | && $(dirname "$0")/internal-tests3.sh \ 7 | && $(dirname "$0")/internal-tests4.sh \ 8 | && $(dirname "$0")/internal-tests5.sh -------------------------------------------------------------------------------- /.test-utils/migrations/1__initial/2__create_post.sql: -------------------------------------------------------------------------------- 1 | -- wtx IN 2 | 3 | CREATE TABLE post ( 4 | id INT NOT NULL PRIMARY KEY, 5 | author_id INT NOT NULL, 6 | title VARCHAR(255) NOT NULL, 7 | description VARCHAR(500) NOT NULL, 8 | content TEXT NOT NULL 9 | ); 10 | 11 | -- wtx OUT 12 | 13 | DROP TABLE post; 14 | -------------------------------------------------------------------------------- /wtx-macros-tests/tests/fail/absent_req_or_res.rs: -------------------------------------------------------------------------------- 1 | #[wtx_macros::pkg] 2 | mod a { 3 | } 4 | 5 | #[wtx_macros::pkg] 6 | mod b { 7 | #[pkg::req_data] 8 | struct Req( 9 | i32 10 | ); 11 | } 12 | 13 | #[wtx_macros::pkg] 14 | mod c { 15 | #[pkg::res_data] 16 | struct Res; 17 | } 18 | 19 | fn main() { 20 | } 21 | -------------------------------------------------------------------------------- /wtx/src/http/server_framework/stream_aux.rs: -------------------------------------------------------------------------------- 1 | /// Auxiliary structures for streams or requests. 2 | pub trait StreamAux: Sized { 3 | /// Initialization 4 | type Init; 5 | 6 | /// Creates a new instance with [`StreamAux::Init`] as well as with a request. 7 | fn stream_aux(init: Self::Init) -> crate::Result; 8 | } 9 | -------------------------------------------------------------------------------- /wtx/src/http2/initial_server_stream_remote.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | http::{Method, Protocol}, 3 | http2::u31::U31, 4 | }; 5 | 6 | #[derive(Debug)] 7 | pub(crate) struct InitialServerStreamRemote { 8 | pub(crate) method: Method, 9 | pub(crate) protocol: Option, 10 | pub(crate) stream_id: U31, 11 | } 12 | -------------------------------------------------------------------------------- /wtx-macros-tests/tests/fail/bad_aux.rs: -------------------------------------------------------------------------------- 1 | #[wtx_macros::pkg(data_format(json), id(FooId))] 2 | mod pkg { 3 | #[pkg::aux] 4 | impl Foo { 5 | type Foo = i32; 6 | } 7 | 8 | #[pkg::req_data] 9 | struct Req( 10 | i32 11 | ); 12 | 13 | #[pkg::res_data] 14 | struct Res; 15 | } 16 | 17 | fn main() { 18 | } 19 | -------------------------------------------------------------------------------- /wtx/src/client_api_framework/tests.rs: -------------------------------------------------------------------------------- 1 | use crate::collection::Vector; 2 | 3 | #[allow(unreachable_pub, reason = "tests")] 4 | #[test] 5 | fn compiles() { 6 | create_packages_aux_wrapper!(); 7 | let _pkg = PkgsAux::from_minimum((), (), ()); 8 | let _pkg = PkgsAux::new((), 0, Vector::new(), (), false, false, ()); 9 | } 10 | -------------------------------------------------------------------------------- /wtx-macros-tests/tests/fail/duplicated_global_pkg_attr.stderr: -------------------------------------------------------------------------------- 1 | error: It is not possible to have more than one declaration of this `pkg` attribute in the same package. 2 | --> tests/fail/duplicated_global_pkg_attr.rs:7:10 3 | | 4 | 7 | #[pkg::req_data] 5 | | ^^^^^^^^ 6 | 7 | error: aborting due to 1 previous error 8 | 9 | -------------------------------------------------------------------------------- /wtx-macros-tests/tests/fail/unknown_transport.stderr: -------------------------------------------------------------------------------- 1 | error: Unknown transport. 2 | --> tests/fail/unknown_transport.rs:1:59 3 | | 4 | 1 | #[wtx_macros::pkg(data_format(json), id(FooId), transport(dasdasd))] 5 | | ^^^^^^^ 6 | 7 | error: aborting due to 1 previous error 8 | 9 | -------------------------------------------------------------------------------- /wtx-macros-tests/tests/fail/bad_params.rs: -------------------------------------------------------------------------------- 1 | #[wtx_macros::pkg(data_format(json), id(FooId))] 2 | mod pkg { 3 | #[derive(Debug)] 4 | #[pkg::params] 5 | pub struct Rfewr; 6 | 7 | #[derive(Debug)] 8 | #[pkg::req_data] 9 | pub struct Req; 10 | 11 | #[pkg::res_data] 12 | struct Res; 13 | } 14 | 15 | fn main() { 16 | } 17 | -------------------------------------------------------------------------------- /wtx/src/http/server_framework/macros.rs: -------------------------------------------------------------------------------- 1 | /// Shortcut that avoids having to explicit import types related to paths. 2 | #[macro_export] 3 | macro_rules! paths { 4 | ( 5 | $( ( $name:expr, $value:expr $(,)? ) ),+ $(,)? 6 | ) => { 7 | ( $( $crate::http::server_framework::PathParams::new($name, $value), )+ ) 8 | }; 9 | } 10 | -------------------------------------------------------------------------------- /wtx-macros-tests/tests/fail/bad_aux.stderr: -------------------------------------------------------------------------------- 1 | error: #[pkg::aux] must be an item implementation with none, one `#[pkg::aux_data]`, one `#[pkg::aux_params]` or both `#[pkg::aux_data]` and `#[pkg::aux_params]` 2 | --> tests/fail/bad_aux.rs:3:10 3 | | 4 | 3 | #[pkg::aux] 5 | | ^^^ 6 | 7 | error: aborting due to 1 previous error 8 | 9 | -------------------------------------------------------------------------------- /wtx/src/http/version.rs: -------------------------------------------------------------------------------- 1 | create_enum! { 2 | #[derive(Clone, Copy, Debug, Default, PartialEq)] 3 | /// HTTP version 4 | pub enum Version { 5 | /// HTTP/1 6 | Http1 = (0, "HTTP/1"), 7 | /// HTTP/1.1 8 | Http1_1 = (1, "HTTP/1.1"), 9 | /// HTTP/2 10 | #[default] 11 | Http2 = (2, "HTTP/2"), 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /wtx/src/database/schema_manager/migration.rs: -------------------------------------------------------------------------------- 1 | mod db_migration; 2 | mod db_migration_group; 3 | mod migration_common; 4 | mod migration_group_common; 5 | mod user_migration; 6 | mod user_migration_group; 7 | 8 | pub use db_migration::*; 9 | pub use db_migration_group::*; 10 | pub use user_migration::*; 11 | pub use user_migration_group::*; 12 | -------------------------------------------------------------------------------- /wtx/src/client_api_framework/network.rs: -------------------------------------------------------------------------------- 1 | //! Auxiliary network function and structures as well as different transport implementations 2 | 3 | #[cfg(feature = "http")] 4 | mod http; 5 | pub mod transport; 6 | mod transport_group; 7 | mod ws; 8 | 9 | #[cfg(feature = "http")] 10 | pub use http::*; 11 | pub use transport_group::*; 12 | pub use ws::*; 13 | -------------------------------------------------------------------------------- /wtx-macros-tests/tests/fail/bad_after_sending.rs: -------------------------------------------------------------------------------- 1 | #[wtx_macros::pkg(data_format(json), id(FooId))] 2 | mod pkg { 3 | #[pkg::after_sending] 4 | async fn after_sending(foo: i32) -> wtx::Result<()> { 5 | Ok(()) 6 | } 7 | 8 | #[pkg::req_data] 9 | struct Req; 10 | 11 | #[pkg::res_data] 12 | struct Res; 13 | } 14 | 15 | fn main() { 16 | } 17 | -------------------------------------------------------------------------------- /wtx-macros-tests/tests/fail/bad_aux_data.rs: -------------------------------------------------------------------------------- 1 | #[wtx_macros::pkg(data_format(json), id(FooId))] 2 | mod pkg { 3 | #[pkg::aux] 4 | impl Foo { 5 | #[pkg::aux_data] 6 | fn fdsfqw() {} 7 | } 8 | 9 | #[pkg::req_data] 10 | struct FooReq( 11 | i32 12 | ); 13 | 14 | #[pkg::res_data] 15 | struct FooRes; 16 | } 17 | 18 | fn main() { 19 | } 20 | -------------------------------------------------------------------------------- /wtx-macros-tests/tests/fail/bad_before_sending.rs: -------------------------------------------------------------------------------- 1 | #[wtx_macros::pkg(data_format(json), id(FooId))] 2 | mod pkg { 3 | #[pkg::before_sending] 4 | async fn before_sending(foo: i32) -> wtx::Result<()> { 5 | Ok(()) 6 | } 7 | 8 | #[pkg::req_data] 9 | struct Req; 10 | 11 | #[pkg::res_data] 12 | struct Res; 13 | } 14 | 15 | fn main() { 16 | } 17 | -------------------------------------------------------------------------------- /wtx/src/database/client.rs: -------------------------------------------------------------------------------- 1 | //! Database clients 2 | 3 | #[cfg(all(any(feature = "mysql", feature = "postgres"), feature = "_integration-tests", test))] 4 | mod integration_tests; 5 | #[cfg(feature = "mysql")] 6 | pub mod mysql; 7 | #[cfg(feature = "postgres")] 8 | pub mod postgres; 9 | #[cfg(any(feature = "mysql", feature = "postgres"))] 10 | mod rdbms; 11 | -------------------------------------------------------------------------------- /wtx/src/database/client/postgres/tys.rs: -------------------------------------------------------------------------------- 1 | mod arguments; 2 | mod array; 3 | mod calendar; 4 | mod collection; 5 | mod ip; 6 | #[cfg(feature = "rust_decimal")] 7 | mod pg_numeric; 8 | mod primitives; 9 | #[cfg(feature = "rust_decimal")] 10 | mod rust_decimal; 11 | #[cfg(feature = "serde_json")] 12 | mod serde_json; 13 | #[cfg(feature = "uuid")] 14 | mod uuid; 15 | -------------------------------------------------------------------------------- /wtx/src/database/database_ty.rs: -------------------------------------------------------------------------------- 1 | create_enum! { 2 | /// Database 3 | #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] 4 | pub enum DatabaseTy { 5 | /// MySql 6 | Mysql = (1, "mysql"), 7 | /// PostgreSQL 8 | Postgres = (2, "postgres"), 9 | /// Unit (Dummy used for testing) 10 | Unit = (5, "unit") 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /wtx-instances/generic-examples/calendar.rs: -------------------------------------------------------------------------------- 1 | //! Basic time operation. 2 | 3 | extern crate wtx; 4 | 5 | use wtx::calendar::{Duration, Instant}; 6 | 7 | fn main() -> wtx::Result<()> { 8 | println!( 9 | "ISO 8601 representation of the next 2 minutes in UTC: {}", 10 | Instant::now_date_time(0)?.add(Duration::from_minutes(2)?)? 11 | ); 12 | Ok(()) 13 | } 14 | -------------------------------------------------------------------------------- /wtx-macros/src/client_api_framework/pkg/data_format_elems.rs: -------------------------------------------------------------------------------- 1 | use proc_macro2::{Ident, TokenStream}; 2 | 3 | #[derive(Debug)] 4 | pub(crate) struct DataFormatElems { 5 | pub(crate) dfe_data_format_builder_fn: Ident, 6 | pub(crate) dfe_ext_req_ctnt_wrapper: Ident, 7 | pub(crate) dfe_ext_res_ctnt_wrapper: Ident, 8 | pub(crate) dfe_pkgs_aux_call: TokenStream, 9 | } 10 | -------------------------------------------------------------------------------- /wtx/src/database/schema_manager/migration/migration_common.rs: -------------------------------------------------------------------------------- 1 | use crate::database::schema_manager::{Repeatability, Uid}; 2 | 3 | #[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] 4 | pub(crate) struct MigrationCommon { 5 | pub(crate) checksum: u64, 6 | pub(crate) name: S, 7 | pub(crate) repeatability: Option, 8 | pub(crate) uid: Uid, 9 | } 10 | -------------------------------------------------------------------------------- /wtx/src/de/dec_error.rs: -------------------------------------------------------------------------------- 1 | use crate::de::protocol::JsonRpcResponseError; 2 | use alloc::boxed::Box; 3 | 4 | /// Decode/EnCode error 5 | #[derive(Debug)] 6 | pub enum DecError { 7 | /// JSON-RPC response error 8 | JsonRpcDecoderErr(Box), 9 | /// `wtx` can not perform this operation due to known limitations. 10 | UnsupportedOperation, 11 | } 12 | -------------------------------------------------------------------------------- /wtx/src/de/protocol/json_rpc.rs: -------------------------------------------------------------------------------- 1 | mod json_rpc_decoder; 2 | mod json_rpc_decoder_error; 3 | mod json_rpc_encoder; 4 | mod json_rpc_notification; 5 | mod json_rpc_notification_params; 6 | 7 | pub use json_rpc_decoder::*; 8 | pub use json_rpc_decoder_error::*; 9 | pub use json_rpc_encoder::*; 10 | pub use json_rpc_notification::*; 11 | pub use json_rpc_notification_params::*; 12 | -------------------------------------------------------------------------------- /wtx/tests/embed-migrations.rs: -------------------------------------------------------------------------------- 1 | //! Embed migrations 2 | 3 | #![cfg(feature = "schema-manager")] 4 | 5 | mod embedded_migrations; 6 | 7 | use wtx::database::schema_manager::Commands; 8 | 9 | /// Compiles 10 | pub async fn compiles() { 11 | let mut commands = Commands::with_executor(()); 12 | commands.migrate_from_groups(embedded_migrations::GROUPS).await.unwrap(); 13 | } 14 | -------------------------------------------------------------------------------- /.scripts/common.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -euxo pipefail 4 | 5 | cargo install rust-tools --git https://github.com/c410-f3r/regular-crates 6 | 7 | export rt='rust-tools --template you-rust' 8 | 9 | export CARGO_TARGET_DIR="$($rt target-dir)" 10 | export RUST_BACKTRACE=1 11 | export RUST_LOG=debug 12 | export RUSTFLAGS="$($rt rust-flags -Asingle-use-lifetimes,-Aunsafe-code)" -------------------------------------------------------------------------------- /wtx/src/de/format/hex.rs: -------------------------------------------------------------------------------- 1 | use crate::misc::{Lease, LeaseMut}; 2 | 3 | /// Decimal decoder/encoder. 4 | #[derive(Debug, Default)] 5 | pub struct Hex; 6 | 7 | impl Lease for Hex { 8 | #[inline] 9 | fn lease(&self) -> &Hex { 10 | self 11 | } 12 | } 13 | 14 | impl LeaseMut for Hex { 15 | #[inline] 16 | fn lease_mut(&mut self) -> &mut Hex { 17 | self 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /wtx/src/http/server_framework/path_params.rs: -------------------------------------------------------------------------------- 1 | /// Router paths 2 | #[derive(Debug)] 3 | pub struct PathParams { 4 | pub(crate) full_path: &'static str, 5 | pub(crate) value: T, 6 | } 7 | 8 | impl PathParams { 9 | /// Creates a new instance 10 | #[inline] 11 | pub const fn new(full_path: &'static str, value: T) -> Self { 12 | Self { full_path, value } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /wtx/src/database/schema_manager/macros.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "std")] 2 | macro_rules! loop_files { 3 | ($buffer:expr, $iter:expr, $n:expr, $cb:expr) => {{ 4 | loop { 5 | for el in $iter.by_ref().take($n) { 6 | $buffer.push(el?)?; 7 | } 8 | if $buffer.is_empty() { 9 | break; 10 | } 11 | $cb; 12 | $buffer.clear(); 13 | } 14 | }}; 15 | } 16 | -------------------------------------------------------------------------------- /wtx/src/http2/reader_data.rs: -------------------------------------------------------------------------------- 1 | use crate::misc::net::PartitionedFilledBuffer; 2 | 3 | #[derive(Debug)] 4 | pub(crate) struct ReaderData { 5 | pub(crate) pfb: PartitionedFilledBuffer, 6 | pub(crate) stream_reader: SR, 7 | } 8 | 9 | impl ReaderData { 10 | pub(crate) fn new(pfb: PartitionedFilledBuffer, stream_reader: SR) -> Self { 11 | Self { pfb, stream_reader } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /wtx-macros-tests/tests/expand/table.stdout: -------------------------------------------------------------------------------- 1 | #![feature(prelude_import)] 2 | #[macro_use] 3 | extern crate std; 4 | #[prelude_import] 5 | use std::prelude::rust_2021::*; 6 | pub struct Foo { 7 | bar: String, 8 | baz: String, 9 | } 10 | impl Foo { 11 | #[doc = r" Fields separated by commas"] 12 | pub(crate) fn fields() -> &'static str { "\"foo\".bar,\"foo\".baz" } 13 | } 14 | 15 | fn main() {} 16 | -------------------------------------------------------------------------------- /.scripts/integration-tests.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | export DATABASE_URI_MYSQL='mysql://wtx:wtx@localhost:3306/wtx' 4 | export DATABASE_URI_POSTGRES='postgres://wtx_scram:wtx@localhost:5432/wtx' 5 | 6 | cargo run --bin wtx-ui --features embed-migrations -- -i .test-utils/migrations.toml -o wtx/tests/embedded_migrations/mod.rs 7 | 8 | cargo test --all-features --release -- --show-output --test-threads=1 --nocapture 9 | -------------------------------------------------------------------------------- /wtx/src/database/client/mysql/protocol/decode_wrapper_protocol.rs: -------------------------------------------------------------------------------- 1 | use crate::misc::Lease; 2 | 3 | #[derive(Debug)] 4 | pub(crate) struct DecodeWrapperProtocol<'inner, 'outer, O> { 5 | pub(crate) bytes: &'outer mut &'inner [u8], 6 | pub(crate) other: O, 7 | } 8 | 9 | impl Lease<[u8]> for DecodeWrapperProtocol<'_, '_, O> { 10 | #[inline] 11 | fn lease(&self) -> &[u8] { 12 | self.bytes 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /.scripts/internal-tests3.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -euxo pipefail 4 | 5 | # WTX 6 | 7 | cargo check --all-features --all-targets 8 | 9 | # WTX Docs 10 | 11 | rustup default nightly-2025-10-31 12 | cargo clean --target-dir mdbook-target 13 | cargo build --all-features --target-dir mdbook-target 14 | mdbook test -L mdbook-target/debug/deps wtx-docs 15 | 16 | RUSTDOCFLAGS="-Dwarnings" cargo doc --all-features 17 | -------------------------------------------------------------------------------- /wtx-macros-tests/tests/fail/bad_before_sending.stderr: -------------------------------------------------------------------------------- 1 | error: `#[pkg::before_sending]` must be an async function named `before_sending` containing any combination of `api: &mut SomeApi`, `params: &mut SomePackageParams` or `res_params: &mut SomeResponseParams`. 2 | --> tests/fail/bad_before_sending.rs:3:10 3 | | 4 | 3 | #[pkg::before_sending] 5 | | ^^^^^^^^^^^^^^ 6 | 7 | error: aborting due to 1 previous error 8 | 9 | -------------------------------------------------------------------------------- /.scripts/integration-tests-mysql.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | export DATABASE_URI_MYSQL='mysql://wtx:wtx@localhost:3307/wtx' 4 | 5 | cargo test --features _async-tests,mysql,_integration-tests --package wtx --release -- --test-threads=1 6 | 7 | export DATABASE_URI_MYSQL='mysql://wtx:wtx@localhost:3308/wtx' 8 | 9 | cargo test --features _async-tests,mysql,_integration-tests --package wtx --release -- --test-threads=1 10 | -------------------------------------------------------------------------------- /wtx-instances/src/grpc.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package wtx; 4 | 5 | service GenericService { 6 | rpc generic_method (GenericRequest) returns (GenericResponse) {} 7 | } 8 | 9 | message GenericRequest { 10 | bytes generic_request_field0 = 1; 11 | uint32 generic_request_field1 = 2; 12 | } 13 | 14 | message GenericResponse { 15 | bytes generic_response_field0 = 1; 16 | uint32 generic_response_field1 = 2; 17 | } -------------------------------------------------------------------------------- /wtx/src/de/protocol/json_rpc/json_rpc_notification_params.rs: -------------------------------------------------------------------------------- 1 | /// A Structured value that holds the parameter values to be used during the invocation of the 2 | /// method. 3 | #[cfg_attr(feature = "serde", derive(serde::Deserialize))] 4 | #[derive(Debug)] 5 | pub struct JsonRpcNotificationParams { 6 | /// Payload 7 | pub result: R, 8 | /// Identifier returned by the counterpart 9 | pub subscription: u64, 10 | } 11 | -------------------------------------------------------------------------------- /wtx-macros-tests/tests/fail/bad_after_sending.stderr: -------------------------------------------------------------------------------- 1 | error: `#[pkg::after_sending]` must be an async function named `after_sending` containing any combination of `api: &mut SomeApi`, `params: &mut SomePackageParams`, `bytes: &[u8]`, and `req_params: &mut SomeRequestParams`. 2 | --> tests/fail/bad_after_sending.rs:3:10 3 | | 4 | 3 | #[pkg::after_sending] 5 | | ^^^^^^^^^^^^^ 6 | 7 | error: aborting due to 1 previous error 8 | 9 | -------------------------------------------------------------------------------- /wtx/src/client_api_framework.rs: -------------------------------------------------------------------------------- 1 | //! A flexible client API framework for writing asynchronous, fast, organizable, scalable and maintainable applications. 2 | 3 | #[macro_use] 4 | mod macros; 5 | 6 | mod api; 7 | mod client_api_framework_error; 8 | pub mod misc; 9 | pub mod network; 10 | pub mod pkg; 11 | #[cfg(test)] 12 | mod tests; 13 | 14 | pub use api::{Api, ApiId}; 15 | pub use client_api_framework_error::ClientApiFrameworkError; 16 | -------------------------------------------------------------------------------- /wtx/src/http/client_pool/client_pool_rm.rs: -------------------------------------------------------------------------------- 1 | use crate::{collection::Vector, http::client_pool::ConnParams}; 2 | use core::marker::PhantomData; 3 | 4 | /// Resource manager for `ClientPool`. 5 | #[derive(Debug)] 6 | pub struct ClientPoolRM { 7 | pub(crate) _aux: A, 8 | pub(crate) _aux_input: AI, 9 | pub(crate) _cert: Option>, 10 | pub(crate) _cp: ConnParams, 11 | pub(crate) _phantom: PhantomData, 12 | } 13 | -------------------------------------------------------------------------------- /wtx-macros-tests/tests/fail/unknown_data_format.stderr: -------------------------------------------------------------------------------- 1 | error: Unknown data format. 2 | --> tests/fail/unknown_data_format.rs:1:1 3 | | 4 | 1 | #[wtx_macros::pkg(data_format(fdsdfs), id(Foo))] 5 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 6 | | 7 | = note: this error originates in the attribute macro `wtx_macros::pkg` (in Nightly builds, run with -Z macro-backtrace for more info) 8 | 9 | error: aborting due to 1 previous error 10 | 11 | -------------------------------------------------------------------------------- /wtx/src/database/schema_manager/repeatability.rs: -------------------------------------------------------------------------------- 1 | create_enum! { 2 | /// Migration repeatability 3 | #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] 4 | pub enum Repeatability { 5 | /// Always runs when executing a migration, regardless of the checksum 6 | Always = (0, "always"), 7 | /// When executing a migration, runs if the checksum has been changed 8 | OnChecksumChange = (1, "on-checksum-change") 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /wtx-docs/src/executor/README.md: -------------------------------------------------------------------------------- 1 | # Executor 2 | 3 | Simple dependency-free runtime intended for tests, toy programs and demonstrations. Performance is not a main concern and you should probably use other executors like `tokio`. 4 | 5 | To use this functionality, it is necessary to activate the `executor` feature. 6 | 7 | ## Example 8 | 9 | ```rust,edition2024,no_run 10 | {{#rustdoc_include ../../../wtx-instances/generic-examples/executor.rs}} 11 | ``` 12 | 13 | -------------------------------------------------------------------------------- /wtx/src/database/client/rdbms/statements_misc.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug)] 2 | pub(crate) struct StatementsMisc { 3 | pub(crate) _aux: A, 4 | pub(crate) columns_len: usize, 5 | pub(crate) rows_len: usize, 6 | pub(crate) types_len: usize, 7 | } 8 | 9 | impl StatementsMisc { 10 | pub(crate) const fn new(aux: A, columns_len: usize, rows_len: usize, types_len: usize) -> Self { 11 | Self { _aux: aux, columns_len, rows_len, types_len } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /wtx/src/rng/crypto_rng.rs: -------------------------------------------------------------------------------- 1 | use crate::rng::Rng; 2 | 3 | /// Marker trait used to indicate that an [`Rng`] implementation is supposed to be 4 | /// cryptographically secure. 5 | #[cfg(feature = "rand-compat")] 6 | pub trait CryptoRng: rand_core::CryptoRng + Rng {} 7 | 8 | /// Marker trait used to indicate that an [`Rng`] implementation is supposed to be 9 | /// cryptographically secure. 10 | #[cfg(not(feature = "rand-compat"))] 11 | pub trait CryptoRng: Rng {} 12 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | updates: 4 | - package-ecosystem: "cargo" 5 | directory: "/" 6 | ignore: 7 | - dependency-name: "*" 8 | update-types: ["version-update:semver-patch"] 9 | schedule: 10 | interval: daily 11 | 12 | - package-ecosystem: "github-actions" 13 | directory: "/" 14 | ignore: 15 | - dependency-name: "*" 16 | update-types: ["version-update:semver-patch"] 17 | schedule: 18 | interval: "daily" 19 | -------------------------------------------------------------------------------- /.scripts/h2load.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -euxo pipefail 4 | 5 | ARG=${1:-""} 6 | if [ "$ARG" != "ci" ]; then 7 | trap "trap - SIGTERM && kill -- -$$" SIGINT SIGTERM EXIT 8 | fi; 9 | 10 | cargo build --bin h2load --features h2load --profile deploy 11 | cargo run --bin h2load --features h2load --profile deploy & 12 | sleep 1 13 | 14 | > /tmp/h2load.txt 15 | h2load -c100 --log-file=/tmp/h2load.txt -m10 -n100000 --no-tls-proto=h2c http://localhost:9000 16 | -------------------------------------------------------------------------------- /wtx/src/http/server_framework/route_match.rs: -------------------------------------------------------------------------------- 1 | use crate::http::OperationMode; 2 | 3 | /// Parameters found in a matched route 4 | #[derive(Clone, Copy, Debug, PartialEq)] 5 | pub struct RouteMatch { 6 | pub(crate) idx: u8, 7 | pub(crate) om: OperationMode, 8 | pub(crate) path: &'static str, 9 | } 10 | 11 | impl RouteMatch { 12 | pub(crate) const fn new(idx: u8, om: OperationMode, path: &'static str) -> Self { 13 | Self { idx, om, path } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /wtx-macros/src/client_api_framework/pkg/keywords.rs: -------------------------------------------------------------------------------- 1 | syn::custom_keyword!(aux_data); 2 | syn::custom_keyword!(aux_params); 3 | syn::custom_keyword!(aux); 4 | syn::custom_keyword!(after_sending); 5 | syn::custom_keyword!(before_sending); 6 | syn::custom_keyword!(field); 7 | syn::custom_keyword!(name); 8 | syn::custom_keyword!(params); 9 | syn::custom_keyword!(pkg); 10 | syn::custom_keyword!(req_data); 11 | syn::custom_keyword!(res_data); 12 | syn::custom_keyword!(transport); 13 | -------------------------------------------------------------------------------- /wtx/src/http/optioned_server.rs: -------------------------------------------------------------------------------- 1 | //! Optioned high-level abstraction for servers. You can use one of listed suggestions or 2 | //! create your own. 3 | // 4 | // FIXME(STABLE): Return type notation 5 | 6 | #[cfg(all(feature = "http2", feature = "tokio"))] 7 | mod http2_tokio; 8 | #[cfg(all(feature = "tokio", feature = "web-socket-handshake"))] 9 | mod web_socket_tokio; 10 | 11 | /// Optioned abstractions of low-level servers. 12 | #[derive(Debug)] 13 | pub struct OptionedServer; 14 | -------------------------------------------------------------------------------- /wtx-macros-tests/tests/fail/bad_field.stderr: -------------------------------------------------------------------------------- 1 | error: Field attributes must be annotated as `#[pkg::field(name = "SomeName")]` 2 | --> tests/fail/bad_field.rs:5:20 3 | | 4 | 5 | pub struct Req(#[pkg::bar] i32); 5 | | ^^^ 6 | 7 | error: expected `name` 8 | --> tests/fail/bad_field.rs:15:31 9 | | 10 | 15 | pub struct Req(#[pkg::field(foo = "1111")] i32); 11 | | ^^^ 12 | 13 | error: aborting due to 2 previous errors 14 | 15 | -------------------------------------------------------------------------------- /wtx/src/database/schema_manager/migration/migration_group_common.rs: -------------------------------------------------------------------------------- 1 | use crate::{database::schema_manager::Uid, misc::Lease}; 2 | 3 | #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] 4 | pub(crate) struct MigrationGroupCommon { 5 | pub(crate) name: S, 6 | pub(crate) uid: Uid, 7 | } 8 | 9 | impl MigrationGroupCommon 10 | where 11 | S: Lease, 12 | { 13 | pub(crate) const fn new(name: S, uid: Uid) -> Self { 14 | Self { name, uid } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /wtx-instances/generic-examples/executor.rs: -------------------------------------------------------------------------------- 1 | //! The `executor` feature allows the execution of asynchronous operations 2 | 3 | extern crate wtx; 4 | extern crate wtx_instances; 5 | 6 | #[wtx::main] 7 | async fn main() { 8 | println!("Hello from program!"); 9 | } 10 | 11 | #[wtx::test] 12 | async fn test_with_runtime(runtime: &wtx::executor::Runtime) { 13 | runtime 14 | .spawn_threaded(async move { 15 | println!("Hello from test!"); 16 | }) 17 | .unwrap(); 18 | } 19 | -------------------------------------------------------------------------------- /wtx/src/de/format/urlencoded.rs: -------------------------------------------------------------------------------- 1 | use crate::misc::{Lease, LeaseMut}; 2 | 3 | /// Type that indicates messages encoded or decoded with percent-encoding 4 | #[derive(Debug, Default)] 5 | pub struct Urlencoded; 6 | 7 | impl Lease for Urlencoded { 8 | #[inline] 9 | fn lease(&self) -> &Urlencoded { 10 | self 11 | } 12 | } 13 | 14 | impl LeaseMut for Urlencoded { 15 | #[inline] 16 | fn lease_mut(&mut self) -> &mut Urlencoded { 17 | self 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /wtx-macros-tests/tests/expand/from_vars.rs: -------------------------------------------------------------------------------- 1 | extern crate alloc; 2 | 3 | #[derive(wtx_macros::FromVars)] 4 | pub struct Foo { 5 | bar0: String, 6 | bar1: Option, 7 | #[from_vars(parse_bar2)] 8 | bar2: u16, 9 | #[from_vars(parse_bar3)] 10 | bar3: Option, 11 | } 12 | 13 | fn parse_bar2(value: String) -> wtx::Result { 14 | Ok(value.parse()?) 15 | } 16 | 17 | fn parse_bar3(value: String) -> wtx::Result { 18 | Ok(value.parse()?) 19 | } 20 | 21 | fn main() {} -------------------------------------------------------------------------------- /wtx-macros-tests/tests/fail/bad_field.rs: -------------------------------------------------------------------------------- 1 | #[wtx_macros::pkg(data_format(json), id(FooId))] 2 | mod pkg { 3 | #[derive(Debug)] 4 | #[pkg::req_data] 5 | pub struct Req(#[pkg::bar] i32); 6 | 7 | #[pkg::res_data] 8 | struct Res; 9 | } 10 | 11 | #[wtx_macros::pkg(data_format(json), id(FooId))] 12 | mod pkg { 13 | #[derive(Debug)] 14 | #[pkg::req_data] 15 | pub struct Req(#[pkg::field(foo = "1111")] i32); 16 | 17 | #[pkg::res_data] 18 | struct Res; 19 | } 20 | 21 | fn main() { 22 | } 23 | -------------------------------------------------------------------------------- /wtx-macros/src/client_api_framework/owned_or_ref.rs: -------------------------------------------------------------------------------- 1 | use quote::ToTokens; 2 | 3 | #[derive(Debug)] 4 | pub(crate) enum OwnedOrRef<'any, T> { 5 | Owned(T), 6 | Ref(&'any T), 7 | } 8 | 9 | impl ToTokens for OwnedOrRef<'_, T> 10 | where 11 | T: ToTokens, 12 | { 13 | fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { 14 | match self { 15 | OwnedOrRef::Owned(elem) => elem.to_tokens(tokens), 16 | OwnedOrRef::Ref(elem) => elem.to_tokens(tokens), 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /wtx/src/rng/fastrand.rs: -------------------------------------------------------------------------------- 1 | impl crate::rng::Rng for fastrand::Rng { 2 | #[inline] 3 | fn u8(&mut self) -> u8 { 4 | self.u8(0..=u8::MAX) 5 | } 6 | 7 | #[inline] 8 | fn u8_4(&mut self) -> [u8; 4] { 9 | self.u32(0..=u32::MAX).to_be_bytes() 10 | } 11 | 12 | #[inline] 13 | fn u8_8(&mut self) -> [u8; 8] { 14 | self.u64(0..=u64::MAX).to_be_bytes() 15 | } 16 | 17 | #[inline] 18 | fn u8_16(&mut self) -> [u8; 16] { 19 | self.u128(0..=u128::MAX).to_be_bytes() 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [profile.deploy] 2 | codegen-units = 1 3 | debug = false 4 | debug-assertions = false 5 | incremental = false 6 | inherits = "release" 7 | lto = true 8 | opt-level = 3 9 | overflow-checks = false 10 | panic = 'abort' 11 | rpath = false 12 | strip = "symbols" 13 | 14 | [profile.profiling] 15 | inherits = "release" 16 | debug = true 17 | 18 | [workspace] 19 | members = [ 20 | "wtx", 21 | "wtx-fuzz", 22 | "wtx-instances", 23 | "wtx-macros", 24 | "wtx-ui" 25 | ] 26 | resolver = "3" 27 | -------------------------------------------------------------------------------- /wtx-macros/src/client_api_framework/pkg/fir/fir_res_item_values.rs: -------------------------------------------------------------------------------- 1 | create_fir_custom_item_values!( 2 | "Expected data response returned by the server.", 3 | FirResItemValues, 4 | fresdiv_fields_attrs, 5 | fresdiv_ident, 6 | fresdiv_item, 7 | fresdiv_params, 8 | fresdiv_ty, 9 | fresdiv_where_predicates, 10 | |this| { 11 | if !this.fresdiv_ident.to_string().ends_with("Res") { 12 | return Err(crate::Error::BadRes(this.fresdiv_ident.span())); 13 | } 14 | Ok(()) 15 | }, 16 | ); 17 | -------------------------------------------------------------------------------- /wtx/src/de/format/quick_protobuf.rs: -------------------------------------------------------------------------------- 1 | use crate::misc::{Lease, LeaseMut}; 2 | 3 | /// Type that indicates the usage of the `quick-protobuf` dependency. 4 | #[derive(Debug, Default)] 5 | pub struct QuickProtobuf; 6 | 7 | impl Lease for QuickProtobuf { 8 | #[inline] 9 | fn lease(&self) -> &QuickProtobuf { 10 | self 11 | } 12 | } 13 | 14 | impl LeaseMut for QuickProtobuf { 15 | #[inline] 16 | fn lease_mut(&mut self) -> &mut QuickProtobuf { 17 | self 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /wtx-macros/src/client_api_framework/pkg/fir/fir_req_item_values.rs: -------------------------------------------------------------------------------- 1 | create_fir_custom_item_values!( 2 | "Expected data request that will be sent to the server.", 3 | FirReqItemValues, 4 | freqdiv_fields_attrs, 5 | freqdiv_ident, 6 | freqdiv_item, 7 | freqdiv_params, 8 | freqdiv_ty, 9 | freqdiv_where_predicates, 10 | |this| { 11 | if !this.freqdiv_ident.to_string().ends_with("Req") { 12 | return Err(crate::Error::BadReq(this.freqdiv_ident.span())); 13 | } 14 | Ok(()) 15 | }, 16 | ); 17 | -------------------------------------------------------------------------------- /wtx-macros/src/client_api_framework/pkg/fir/fir_params_items_values.rs: -------------------------------------------------------------------------------- 1 | create_fir_custom_item_values!( 2 | "Custom local parameters used before and after the issuing of a request.", 3 | FirParamsItemValues, 4 | fpiv_fields_attrs, 5 | fpiv_ident, 6 | fpiv_item, 7 | fpiv_params, 8 | fpiv_ty, 9 | fpiv_where_predicates, 10 | |this| { 11 | if !this.fpiv_ident.to_string().ends_with("Params") { 12 | return Err(crate::Error::BadParams(this.fpiv_ident.span())); 13 | } 14 | Ok(()) 15 | }, 16 | ); 17 | -------------------------------------------------------------------------------- /wtx/src/de/protocol/json_rpc/json_rpc_notification.rs: -------------------------------------------------------------------------------- 1 | use crate::de::protocol::JsonRpcNotificationParams; 2 | use alloc::boxed::Box; 3 | 4 | /// A request object without an "id" member. Generally used with WebSocket connections. 5 | #[cfg_attr(feature = "serde", derive(serde::Deserialize))] 6 | #[derive(Debug)] 7 | pub struct JsonRpcNotification { 8 | /// Name of the method invoked. 9 | pub method: Option>, 10 | /// See [`JsonRpcNotificationParams`]. 11 | pub params: JsonRpcNotificationParams, 12 | } 13 | -------------------------------------------------------------------------------- /wtx/src/de/protocol/json_rpc/json_rpc_decoder_error.rs: -------------------------------------------------------------------------------- 1 | use alloc::boxed::Box; 2 | 3 | /// When a rpc call encounters an error. 4 | #[cfg_attr(feature = "serde", derive(serde::Deserialize))] 5 | #[derive(Debug)] 6 | pub struct JsonRpcResponseError { 7 | /// Indicates the error type that occurred. 8 | pub code: i32, 9 | /// Additional information about the error 10 | #[cfg(feature = "serde_json")] 11 | pub data: Option, 12 | /// Short description of the error. 13 | pub message: Box, 14 | } 15 | -------------------------------------------------------------------------------- /wtx/src/de/format/decode_wrapper.rs: -------------------------------------------------------------------------------- 1 | use crate::misc::Lease; 2 | 3 | /// Struct used for decoding different formats. 4 | #[derive(Debug, PartialEq)] 5 | pub struct DecodeWrapper<'de> { 6 | pub(crate) bytes: &'de [u8], 7 | } 8 | 9 | impl<'de> DecodeWrapper<'de> { 10 | /// New instance 11 | #[inline] 12 | pub const fn new(bytes: &'de [u8]) -> Self { 13 | Self { bytes } 14 | } 15 | } 16 | 17 | impl Lease<[u8]> for DecodeWrapper<'_> { 18 | #[inline] 19 | fn lease(&self) -> &[u8] { 20 | self.bytes 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /wtx-ui/src/main.rs: -------------------------------------------------------------------------------- 1 | //! WTX - Cli 2 | 3 | #[cfg(feature = "clap")] 4 | mod clap; 5 | #[cfg(feature = "embed-migrations")] 6 | mod embed_migrations; 7 | #[cfg(feature = "http-client")] 8 | mod http_client; 9 | #[cfg(feature = "schema-manager")] 10 | mod schema_manager; 11 | #[cfg(feature = "web-socket")] 12 | mod web_socket; 13 | 14 | #[allow(clippy::unwrap_in_result, reason = "false-position")] 15 | #[tokio::main] 16 | async fn main() -> wtx::Result<()> { 17 | #[cfg(feature = "clap")] 18 | clap::init().await?; 19 | Ok(()) 20 | } 21 | -------------------------------------------------------------------------------- /wtx/src/database/client/mysql/flag.rs: -------------------------------------------------------------------------------- 1 | create_enum! { 2 | #[derive(Clone, Copy, Debug, Eq, PartialEq)] 3 | pub(crate) enum Flag { 4 | NotNull = (1), 5 | PrimaryKey = (2), 6 | UniqueKey = (4), 7 | MultipleKey = (8), 8 | Blob = (16), 9 | Unsigned = (32), 10 | Zerofill = (64), 11 | Binary = (128), 12 | Enum = (256), 13 | AutoIncrement = (512), 14 | Timestamp = (1024), 15 | Set = (2048), 16 | NoDefaultValue = (4096), 17 | OnUpdateNow = (8192), 18 | Num = (32768), 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /wtx/src/de/protocol.rs: -------------------------------------------------------------------------------- 1 | //! Different request and response formats. 2 | //! 3 | //! #### Noteworthy 4 | //! 5 | //! The `GraphQL` structure only contains the data expected for requests and responses, 6 | //! which means that the elaboration of queries or other elements should be handled elsewhere. For 7 | //! example, you can write your own operations or rely on third-parties dependencies. 8 | 9 | mod graph_ql; 10 | mod json_rpc; 11 | mod misc; 12 | mod verbatim; 13 | 14 | pub use graph_ql::*; 15 | pub use json_rpc::*; 16 | pub use verbatim::*; 17 | -------------------------------------------------------------------------------- /wtx/src/http/misc.rs: -------------------------------------------------------------------------------- 1 | use crate::http::{Headers, KnownHeaderName, Method, Protocol}; 2 | 3 | /// Verifies if the initial received HTTP/2 headers represent a WebSocket connection. 4 | #[inline] 5 | pub fn is_web_socket_handshake( 6 | headers: &Headers, 7 | method: Method, 8 | protocol: Option, 9 | ) -> bool { 10 | let header = KnownHeaderName::SecWebsocketVersion.into(); 11 | method == Method::Connect 12 | && protocol == Some(Protocol::WebSocket) 13 | && headers.get_by_name(header).map(|el| el.value) == Some("13") 14 | } 15 | -------------------------------------------------------------------------------- /wtx/src/http/session/session_error.rs: -------------------------------------------------------------------------------- 1 | /// Session error 2 | #[derive(Debug)] 3 | pub enum SessionError { 4 | /// Received a session that is expired. 5 | ExpiredSession, 6 | /// Received a request which CSRF token differs from the stored CSRF token. 7 | InvalidCsrfRequest, 8 | /// Received a session that differs from the stored session. 9 | InvalidStoredSession, 10 | /// REceived a session that doesn't exist in the store 11 | MissingStoredSession, 12 | /// Path required a session, but there was none 13 | RequiredSession, 14 | } 15 | -------------------------------------------------------------------------------- /wtx/src/database/client/mysql/protocol/ping_req.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | database::client::mysql::{ 3 | command::Command, 4 | protocol::{Protocol, encode_wrapper_protocol::EncodeWrapperProtocol}, 5 | }, 6 | de::Encode, 7 | }; 8 | 9 | pub(crate) struct PingReq; 10 | 11 | impl Encode> for PingReq 12 | where 13 | E: From, 14 | { 15 | #[inline] 16 | fn encode(&self, ew: &mut EncodeWrapperProtocol<'_>) -> Result<(), E> { 17 | ew.encode_buffer.push(Command::ComPing.into())?; 18 | Ok(()) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /wtx/src/http/server_framework/methods.rs: -------------------------------------------------------------------------------- 1 | pub(crate) mod delete; 2 | pub(crate) mod get; 3 | pub(crate) mod json; 4 | pub(crate) mod patch; 5 | pub(crate) mod post; 6 | pub(crate) mod put; 7 | pub(crate) mod web_socket; 8 | 9 | use crate::http::{HttpError, Method}; 10 | 11 | fn check_method(expected: Method, received: Method) -> Result<(), E> 12 | where 13 | E: From, 14 | { 15 | if expected != received { 16 | return Err(E::from(crate::Error::from(HttpError::UnexpectedHttpMethod { expected }))); 17 | } 18 | Ok(()) 19 | } 20 | -------------------------------------------------------------------------------- /wtx-macros-tests/tests/fail/incorrect_json_rpc_data_format.stderr: -------------------------------------------------------------------------------- 1 | error: JSON-RPC expects the name of its method. For example, `#[pkg(data_format(json_rpc("method")))]` 2 | --> tests/fail/incorrect_json_rpc_data_format.rs:1:1 3 | | 4 | 1 | #[wtx_macros::pkg(data_format(json_rpc(Bar)), id(Foo))] 5 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 6 | | 7 | = note: this error originates in the attribute macro `wtx_macros::pkg` (in Nightly builds, run with -Z macro-backtrace for more info) 8 | 9 | error: aborting due to 1 previous error 10 | 11 | -------------------------------------------------------------------------------- /wtx-macros-tests/tests/fail/mandatory_outer_attrs_are_not_present.stderr: -------------------------------------------------------------------------------- 1 | error: All packages must have a `data_format` and an `id` attribute. For example, #[pkg(data_format(json), id(SomeApi))] 2 | --> tests/fail/mandatory_outer_attrs_are_not_present.rs:1:1 3 | | 4 | 1 | #[wtx_macros::pkg(data_format(), id(Foo))] 5 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 6 | | 7 | = note: this error originates in the attribute macro `wtx_macros::pkg` (in Nightly builds, run with -Z macro-backtrace for more info) 8 | 9 | error: aborting due to 1 previous error 10 | 11 | -------------------------------------------------------------------------------- /wtx/src/database/client/mysql/protocol/auth_switch_req.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | database::client::mysql::protocol::{Protocol, encode_wrapper_protocol::EncodeWrapperProtocol}, 3 | de::Encode, 4 | }; 5 | 6 | pub(crate) struct AuthSwitchReq<'bytes>(pub(crate) &'bytes [u8]); 7 | 8 | impl Encode> for AuthSwitchReq<'_> 9 | where 10 | E: From, 11 | { 12 | #[inline] 13 | fn encode(&self, ew: &mut EncodeWrapperProtocol<'_>) -> Result<(), E> { 14 | ew.encode_buffer.extend_from_copyable_slice(self.0)?; 15 | Ok(()) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /wtx/src/de/format/encode_wrapper.rs: -------------------------------------------------------------------------------- 1 | use crate::{collection::Vector, misc::Lease}; 2 | 3 | /// Struct used for encoding different formats. 4 | #[derive(Debug)] 5 | pub struct EncodeWrapper<'any> { 6 | pub(crate) vector: &'any mut Vector, 7 | } 8 | 9 | impl<'any> EncodeWrapper<'any> { 10 | /// New instance 11 | #[inline] 12 | pub const fn new(vector: &'any mut Vector) -> Self { 13 | Self { vector } 14 | } 15 | } 16 | 17 | impl Lease<[u8]> for EncodeWrapper<'_> { 18 | #[inline] 19 | fn lease(&self) -> &[u8] { 20 | self.vector 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /wtx/src/database/schema_manager/commands/clear.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | collection::Vector, 3 | database::schema_manager::{Commands, SchemaManagement}, 4 | de::DEController, 5 | }; 6 | use alloc::string::String; 7 | 8 | impl Commands 9 | where 10 | E: SchemaManagement, 11 | { 12 | /// Tries to clear all objects of a database, including separated namespaces/schemas. 13 | #[inline] 14 | pub async fn clear(&mut self) -> Result<(), ::Error> { 15 | self.executor.clear((&mut String::new(), &mut Vector::new())).await 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /.scripts/curl.sh: -------------------------------------------------------------------------------- 1 | set -euxo pipefail 2 | 3 | PWD="$(pwd)" 4 | 5 | if [ -d "./curl" ]; then 6 | cd curl/tests 7 | else 8 | #sudo apt install autoconf libnghttp2-dev libtool libpsl-dev -y 9 | git clone --branch curl-8_9_1 --depth 1 https://github.com/curl/curl 10 | cd curl 11 | autoreconf -fi 12 | ./configure --enable-debug --with-nghttp2 --without-ssl 13 | make 14 | cd tests/server 15 | make 16 | cd .. 17 | fi 18 | 19 | cargo build --bin wtx-ui --features _curl,http-client --release 20 | ./runtests.pl -d -n -c "$PWD/../../target/release/wtx-ui" -------------------------------------------------------------------------------- /wtx/src/calendar/macros.rs: -------------------------------------------------------------------------------- 1 | macro_rules! manage_out_of_bounds { 2 | (@one, $min:expr, $max:expr, $elem:expr, $to:expr $(,)?) => { 3 | manage_out_of_bounds!($min, $max, $elem, $to = $to.wrapping_add(1), $to = $to.wrapping_sub(1)) 4 | }; 5 | ($min:expr, $max:expr, $elem:expr, $greater:expr, $lesser:expr $(,)?) => { 6 | if $elem >= $max { 7 | $elem = $elem.wrapping_sub($max.wrapping_sub($min)); 8 | $greater 9 | } else if $elem < $min { 10 | $elem = $elem.wrapping_add($max.wrapping_sub($min)); 11 | $lesser 12 | } else { 13 | } 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /.scripts/autobahn/fuzzingserver-min.json: -------------------------------------------------------------------------------- 1 | { 2 | "cases": [ 3 | "1.*", 4 | "2.*", 5 | "3.*", 6 | "4.*", 7 | "5.*", 8 | "6.*", 9 | "7.*", 10 | "8.*", 11 | "9.*", 12 | "10.*", 13 | "12.1.1", 14 | "12.2.1", 15 | "12.3.1", 16 | "12.4.1", 17 | "12.5.1", 18 | "13.1.1", 19 | "13.2.1", 20 | "13.3.1", 21 | "13.4.1", 22 | "13.5.1", 23 | "13.6.1", 24 | "13.7.1" 25 | ], 26 | "exclude-agent-cases": {}, 27 | "exclude-cases": [], 28 | "outdir": "/autobahn/reports/fuzzingserver", 29 | "url": "ws://127.0.0.1:9080" 30 | } -------------------------------------------------------------------------------- /wtx/src/collection/expansion_ty.rs: -------------------------------------------------------------------------------- 1 | /// Used in operations that expand collections. 2 | #[derive(Clone, Copy, Debug)] 3 | pub enum ExpansionTy { 4 | /// Buffer should be modified with more elements 5 | Additional(usize), 6 | /// Buffer should be modified using the exact specified length. 7 | Len(usize), 8 | } 9 | 10 | impl ExpansionTy { 11 | pub(crate) fn params(self, len: usize) -> Option<(usize, usize)> { 12 | Some(match self { 13 | Self::Additional(elem) => (elem, len.checked_add(elem)?), 14 | Self::Len(elem) => (elem.checked_sub(len)?, elem), 15 | }) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /wtx/src/http/client_pool/integration_tests.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | http::{HttpClient, ReqBuilder, ReqResBuffer, client_pool::ClientPoolBuilder}, 3 | misc::UriRef, 4 | }; 5 | 6 | #[tokio::test] 7 | async fn popular_sites() { 8 | send_recv("https://github.com".into()).await; 9 | send_recv("https://duckduckgo.com".into()).await; 10 | send_recv("https://www.google.com".into()).await; 11 | } 12 | 13 | async fn send_recv(uri: UriRef<'_>) { 14 | let client = ClientPoolBuilder::tokio_rustls(1).build(); 15 | let _res = client.send_req_recv_res(ReqResBuffer::empty(), ReqBuilder::get(uri)).await.unwrap(); 16 | } 17 | -------------------------------------------------------------------------------- /wtx/src/executor/curr_thread_waker.rs: -------------------------------------------------------------------------------- 1 | use alloc::{sync::Arc, task::Wake}; 2 | use core::task::Waker; 3 | use std::thread; 4 | 5 | pub(crate) struct CurrThreadWaker { 6 | pub(crate) thread: thread::Thread, 7 | } 8 | 9 | impl CurrThreadWaker { 10 | pub(crate) fn waker() -> Waker { 11 | Waker::from(Arc::new(CurrThreadWaker { thread: thread::current() })) 12 | } 13 | } 14 | 15 | impl Wake for CurrThreadWaker { 16 | #[inline] 17 | fn wake(self: Arc) { 18 | self.thread.unpark(); 19 | } 20 | 21 | #[inline] 22 | fn wake_by_ref(self: &Arc) { 23 | self.thread.unpark(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /wtx-macros-tests/tests/fail/no_enum_struct_or_type.rs: -------------------------------------------------------------------------------- 1 | #[wtx_macros::pkg(data_format(json), id(FooId))] 2 | mod pkg { 3 | #[pkg::req_data] 4 | fn foo() {} 5 | 6 | #[pkg::res_data] 7 | struct Res; 8 | } 9 | 10 | #[wtx_macros::pkg(data_format(json), id(FooId))] 11 | mod pkg { 12 | #[pkg::req_data] 13 | struct Req; 14 | 15 | #[pkg::res_data] 16 | fn foo() {} 17 | } 18 | 19 | #[wtx_macros::pkg(data_format(json), id(FooId))] 20 | mod pkg { 21 | #[pkg::params] 22 | fn foo() {} 23 | 24 | #[pkg::req_data] 25 | struct Req; 26 | 27 | #[pkg::res_data] 28 | struct Res; 29 | } 30 | 31 | fn main() { 32 | } 33 | -------------------------------------------------------------------------------- /wtx-macros-tests/tests/fail/no_enum_struct_or_type.stderr: -------------------------------------------------------------------------------- 1 | error: Invalid item. Expected enum, struct or type. 2 | --> tests/fail/no_enum_struct_or_type.rs:3:10 3 | | 4 | 3 | #[pkg::req_data] 5 | | ^^^^^^^^ 6 | 7 | error: Invalid item. Expected enum, struct or type. 8 | --> tests/fail/no_enum_struct_or_type.rs:15:10 9 | | 10 | 15 | #[pkg::res_data] 11 | | ^^^^^^^^ 12 | 13 | error: Invalid item. Expected enum, struct or type. 14 | --> tests/fail/no_enum_struct_or_type.rs:21:10 15 | | 16 | 21 | #[pkg::params] 17 | | ^^^^^^ 18 | 19 | error: aborting due to 3 previous errors 20 | 21 | -------------------------------------------------------------------------------- /wtx-ui/README.md: -------------------------------------------------------------------------------- 1 | # WTX UI 2 | 3 | `wtx-ui` is a standalone crate intended to allow interactions with the (`wtx`)[https://github.com/c410-f3r/wtx] project through an interface. At the current time only CLI interfaces are available. 4 | 5 | - Embeds SQL migrations for `schema-manager`. Activation feature is called `embed-migrations`. 6 | - Runs SQL migrations for `schema-manager`. Activation feature is called `schema-manager` or `schema-manager-dev`. 7 | - Performs very basic WebSocket Client/Server operations. Activation feature is called `web-socket`. 8 | - Makes `GET` requests to arbitrary URIs. Activation feature is called `http-client`. -------------------------------------------------------------------------------- /wtx-macros-tests/tests/pass/data_with_params.rs: -------------------------------------------------------------------------------- 1 | //! Endpoint with data and parameters 2 | 3 | wtx::create_packages_aux_wrapper!(); 4 | 5 | type Api = (); 6 | 7 | #[wtx_macros::pkg(data_format(json), id(super::Api), transport(http))] 8 | mod pkg { 9 | #[pkg::aux] 10 | impl super::PkgsAux<(), (), ()> {} 11 | 12 | #[derive(Debug)] 13 | #[pkg::params] 14 | pub struct FooParams<'any> { 15 | bar: &'any str, 16 | } 17 | 18 | #[derive(Debug)] 19 | #[pkg::req_data] 20 | pub(crate) struct FooReq { 21 | bar: i32 22 | } 23 | 24 | #[pkg::res_data] 25 | pub(crate) type FooRes = (); 26 | } 27 | 28 | fn main() { 29 | } 30 | -------------------------------------------------------------------------------- /wtx-fuzz/Cargo.toml: -------------------------------------------------------------------------------- 1 | [[bin]] 2 | name = "date_time" 3 | path = "date_time.rs" 4 | required-features = ["libfuzzer-sys/link_libfuzzer"] 5 | 6 | [[bin]] 7 | name = "web-socket" 8 | path = "web_socket.rs" 9 | required-features = ["libfuzzer-sys/link_libfuzzer"] 10 | 11 | [dependencies] 12 | libfuzzer-sys = { default-features = false, version = "0.4" } 13 | wtx = { default-features = false, features = ["arbitrary", "executor", "web-socket"], path = "../wtx" } 14 | 15 | [package] 16 | edition = "2024" 17 | name = "wtx-fuzz" 18 | publish = false 19 | rust-version = "1.89" 20 | version = "0.0.0" 21 | 22 | [package.metadata] 23 | cargo-fuzz = true 24 | -------------------------------------------------------------------------------- /wtx-macros/src/client_api_framework/pkg/fir/fir_after_sending_item_values.rs: -------------------------------------------------------------------------------- 1 | create_fir_hook_item_values!( 2 | FirAfterSendingItemValues, 3 | fasiv_fn_call_idents, 4 | fasiv_item, 5 | _fasiv_params, 6 | fasiv_where_predicates, 7 | |arg| { 8 | Some(match arg { 9 | "api" => quote::quote!(_api.lease_mut()), 10 | "bytes" => quote::quote!(_bytes), 11 | "drsr" => quote::quote!(_drsr), 12 | "params" => quote::quote!(&mut self.params), 13 | "trans" => quote::quote!(_trans), 14 | "trans_params" => quote::quote!(_trans_params), 15 | _ => return None, 16 | }) 17 | }, 18 | BadAfterSending, 19 | ); 20 | -------------------------------------------------------------------------------- /wtx-macros/src/client_api_framework/pkg/fir/fir_before_sending_item_values.rs: -------------------------------------------------------------------------------- 1 | create_fir_hook_item_values!( 2 | FirBeforeSendingItemValues, 3 | fbsiv_fn_call_idents, 4 | fbsiv_item, 5 | _fasiv_params, 6 | fbsiv_where_predicates, 7 | |arg| { 8 | Some(match arg { 9 | "api" => quote::quote!(_api.lease_mut()), 10 | "bytes" => quote::quote!(_bytes), 11 | "drsr" => quote::quote!(_drsr), 12 | "params" => quote::quote!(&mut self.params), 13 | "trans" => quote::quote!(_trans), 14 | "trans_params" => quote::quote!(_trans_params), 15 | _ => return None, 16 | }) 17 | }, 18 | BadBeforeSending, 19 | ); 20 | -------------------------------------------------------------------------------- /wtx/src/http/server_framework/server_framework_error.rs: -------------------------------------------------------------------------------- 1 | /// Server Framework Error 2 | #[derive(Debug)] 3 | pub enum ServerFrameworkError { 4 | /// Client requested a CORS header that isn't allowed 5 | ForbiddenCorsHeader, 6 | /// Client requested a CORS method that isn't allowed 7 | ForbiddenCorsMethod, 8 | /// Client requested a CORS origin that isn't allowed 9 | ForbiddenCorsOrigin, 10 | /// Client sent a request with invalid WebSocket tunneling parameters 11 | InvalidWebSocketParameters, 12 | /// Entered in a route that has an incompatible operation mode 13 | OperationModeMismatch, 14 | /// Unknown path 15 | UnknownPath, 16 | } 17 | -------------------------------------------------------------------------------- /wtx-docs/src/secrets/README.md: -------------------------------------------------------------------------------- 1 | # Secrets 2 | 3 | The `Secret` struct is a container for sensitive data that needs to be sustained in memory for an extended period. Holds locked and encrypted heap-allocated bytes that are decrypted on demand to protect against inspection techniques. 4 | 5 | Please keep in mind that this is not a silver bullet, but rather an additional layer of protection. For example, when the `peek` closure is executing, the plaintext secret will exist transiently in CPU registers and caches, which is unavoidable. 6 | 7 | ## Example 8 | 9 | ```rust,edition2024,no_run 10 | {{#rustdoc_include ../../../wtx-instances/generic-examples/secrets.rs}} 11 | ``` -------------------------------------------------------------------------------- /wtx/src/database/client/mysql/protocol/encode_wrapper_protocol.rs: -------------------------------------------------------------------------------- 1 | use crate::{collection::Vector, misc::Lease}; 2 | 3 | pub(crate) struct EncodeWrapperProtocol<'any> { 4 | pub(crate) capabilities: &'any mut u64, 5 | pub(crate) encode_buffer: &'any mut Vector, 6 | } 7 | 8 | impl<'any> EncodeWrapperProtocol<'any> { 9 | pub(crate) const fn new( 10 | capabilities: &'any mut u64, 11 | encode_buffer: &'any mut Vector, 12 | ) -> Self { 13 | Self { capabilities, encode_buffer } 14 | } 15 | } 16 | 17 | impl Lease<[u8]> for EncodeWrapperProtocol<'_> { 18 | #[inline] 19 | fn lease(&self) -> &[u8] { 20 | self.encode_buffer 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /wtx/src/database/client/mysql/protocol/query_req.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | database::client::mysql::{ 3 | command::Command, 4 | protocol::{Protocol, encode_wrapper_protocol::EncodeWrapperProtocol}, 5 | }, 6 | de::Encode, 7 | }; 8 | 9 | pub(crate) struct QueryReq<'any> { 10 | pub(crate) query: &'any [u8], 11 | } 12 | 13 | impl Encode> for QueryReq<'_> 14 | where 15 | E: From, 16 | { 17 | #[inline] 18 | fn encode(&self, ew: &mut EncodeWrapperProtocol<'_>) -> Result<(), E> { 19 | let _ = 20 | ew.encode_buffer.extend_from_copyable_slices([&[Command::ComQuery.into()], self.query])?; 21 | Ok(()) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /.scripts/autobahn/fuzzingclient-min.json: -------------------------------------------------------------------------------- 1 | { 2 | "cases": [ 3 | "1.*", 4 | "2.*", 5 | "3.*", 6 | "4.*", 7 | "5.*", 8 | "6.*", 9 | "7.*", 10 | "8.*", 11 | "9.*", 12 | "10.*", 13 | "12.1.1", 14 | "12.2.1", 15 | "12.3.1", 16 | "12.4.1", 17 | "12.5.1", 18 | "13.1.1", 19 | "13.2.1", 20 | "13.3.1", 21 | "13.4.1", 22 | "13.5.1", 23 | "13.6.1", 24 | "13.7.1" 25 | ], 26 | "exclude-agent-cases": {}, 27 | "exclude-cases": [], 28 | "outdir": "/autobahn/reports/fuzzingclient", 29 | "servers": [ 30 | { 31 | "agent": "wtx", 32 | "url": "ws://127.0.0.1:9070" 33 | } 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /wtx/src/http2/continuation_frame.rs: -------------------------------------------------------------------------------- 1 | use crate::http2::{ 2 | common_flags::CommonFlags, 3 | frame_init::{FrameInit, FrameInitTy}, 4 | u31::U31, 5 | }; 6 | 7 | #[derive(Debug)] 8 | pub(crate) struct ContinuationFrame { 9 | cf: CommonFlags, 10 | stream_id: U31, 11 | } 12 | 13 | impl ContinuationFrame { 14 | pub(crate) const fn new(stream_id: U31) -> Self { 15 | Self { cf: CommonFlags::empty(), stream_id } 16 | } 17 | 18 | pub(crate) const fn bytes(&self) -> [u8; 9] { 19 | FrameInit::new(self.cf, 0, self.stream_id, FrameInitTy::Continuation).bytes() 20 | } 21 | 22 | pub(crate) const fn set_eoh(&mut self) { 23 | self.cf.set_eoh(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /wtx-docs/src/ui-tools/README.md: -------------------------------------------------------------------------------- 1 | # UI Tools 2 | 3 | `wtx-ui` is a standalone crate intended to allow interactions with the [`wtx`](https://github.com/c410-f3r/wtx) project through an user interface. At the current time only CLI interfaces are available. 4 | 5 | - Embeds SQL migrations for `schema-manager`. Activation feature is called `embed-migrations`. 6 | - Runs SQL migrations managed by `schema-manager`. Activation feature is called `schema-manager` or `schema-manager-dev`. 7 | - Performs very basic WebSocket Client/Server operations. Activation feature is called `web-socket`. 8 | - Makes requests to arbitrary URIs mimicking the interface of `cURL`. Activation feature is called `http-client`. -------------------------------------------------------------------------------- /clippy.toml: -------------------------------------------------------------------------------- 1 | cognitive-complexity-threshold = 50 2 | disallowed-methods = [ 3 | "char::encode_utf8", 4 | "core::str::from_utf8", 5 | "core::sync::atomic::fence", 6 | "slice::rsplit", 7 | "slice::split", 8 | "str::rsplit", 9 | ] 10 | disallowed-types = [ 11 | "alloc::sync::Arc", 12 | "core::sync::atomic::AtomicU32", 13 | "core::sync::atomic::AtomicU64", 14 | "core::sync::atomic::AtomicUsize", 15 | "std::collections::HashMap", 16 | "std::collections::HashSet" 17 | ] 18 | doc-valid-idents = [ 19 | "MiB", 20 | "PostgreSQL", 21 | "WebSocket", 22 | "WebSockets", 23 | "WebTransport" 24 | ] 25 | too-many-arguments-threshold = 16 26 | type-complexity-threshold = 500 27 | -------------------------------------------------------------------------------- /wtx-macros-tests/tests/pass/pkgs_aux_bounds.rs: -------------------------------------------------------------------------------- 1 | //! `#[pkg::aux]` accepts bounds 2 | 3 | wtx::create_packages_aux_wrapper!(); 4 | 5 | type Api = (); 6 | 7 | /// Generic API 8 | pub trait GenericApi {} 9 | 10 | impl GenericApi for &mut Api {} 11 | impl GenericApi for Api {} 12 | impl GenericApi for Box {} 13 | 14 | #[wtx_macros::pkg(data_format(json), id(super::Api), transport(http))] 15 | mod pkg { 16 | #[pkg::aux] 17 | impl super::PkgsAux 18 | where 19 | A: super::GenericApi 20 | {} 21 | 22 | #[pkg::req_data] 23 | pub(crate) type FooReq<'any> = &'any (); 24 | 25 | #[pkg::res_data] 26 | pub(crate) type FooRes = (); 27 | } 28 | 29 | fn main() { 30 | } 31 | -------------------------------------------------------------------------------- /wtx/src/database/client/mysql/protocol/prepare_req.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | database::client::mysql::{ 3 | command::Command, 4 | protocol::{Protocol, encode_wrapper_protocol::EncodeWrapperProtocol}, 5 | }, 6 | de::Encode, 7 | }; 8 | 9 | pub(crate) struct PrepareReq<'any> { 10 | pub(crate) query: &'any [u8], 11 | } 12 | 13 | impl Encode> for PrepareReq<'_> 14 | where 15 | E: From, 16 | { 17 | #[inline] 18 | fn encode(&self, ew: &mut EncodeWrapperProtocol<'_>) -> Result<(), E> { 19 | let _ = ew 20 | .encode_buffer 21 | .extend_from_copyable_slices([&[Command::ComStmtPrepare.into()], self.query])?; 22 | Ok(()) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /wtx-docs/src/http-client-pool/README.md: -------------------------------------------------------------------------------- 1 | # HTTP Client Pool 2 | 3 | High-level pool of HTTP clients where multiple connections that can be referenced in concurrent scenarios. 4 | 5 | Reuses valid connections and recycles dropped communications to minimize contention and latency. Instances are created on-demand and maintained for subsequent requests to the same host. 6 | 7 | Also useful because HTTP/2 and HTTP/3 expect long-lived sessions by default unlike HTTP/1. 8 | 9 | To use this functionality, it is necessary to activate the `http-client-pool` feature. 10 | 11 | ## Example 12 | 13 | ```rust,edition2024,no_run 14 | {{#rustdoc_include ../../../wtx-instances/generic-examples/http-client-pool.rs}} 15 | ``` -------------------------------------------------------------------------------- /wtx/src/database/schema_manager/migration_status.rs: -------------------------------------------------------------------------------- 1 | /// Status of a migration operation; 2 | #[derive(Debug)] 3 | pub struct MigrationStatus { 4 | /// The number of applied migrations performed in the current operation. 5 | pub curr_applied_migrations: u64, 6 | /// The last migration ID stored in the database after applying a operation. 7 | pub curr_last_db_migration_uid: Option, 8 | /// The migration group user ID 9 | pub mg_uid: u32, 10 | /// The last migration ID stored in the database before applying a operation. 11 | pub prev_last_db_migration_uid: Option, 12 | /// The number of migrations stored in the database before applying a operation. 13 | pub prev_db_migrations: u64, 14 | } 15 | -------------------------------------------------------------------------------- /wtx/src/database/client/mysql/encode_wrapper.rs: -------------------------------------------------------------------------------- 1 | use crate::{collection::Vector, misc::Lease}; 2 | 3 | /// Struct used for encoding elements in MySQL. 4 | #[derive(Debug)] 5 | pub struct EncodeWrapper<'any> { 6 | buffer: &'any mut Vector, 7 | } 8 | 9 | impl<'any> EncodeWrapper<'any> { 10 | pub(crate) const fn new(buffer: &'any mut Vector) -> Self { 11 | Self { buffer } 12 | } 13 | 14 | /// Buffer used to encode messages that will be sent to MySQL. 15 | #[inline] 16 | pub const fn buffer(&mut self) -> &mut Vector { 17 | self.buffer 18 | } 19 | } 20 | 21 | impl Lease<[u8]> for EncodeWrapper<'_> { 22 | #[inline] 23 | fn lease(&self) -> &[u8] { 24 | self.buffer 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /wtx-macros-tests/tests/fail/absent_req_or_res.stderr: -------------------------------------------------------------------------------- 1 | error: The `#[pkg]` module must have an inner `#[pkg::req_data]` element and an inner `#[pkg::res_data]` element. 2 | --> tests/fail/absent_req_or_res.rs:2:5 3 | | 4 | 2 | mod a { 5 | | ^ 6 | 7 | error: The `#[pkg]` module must have an inner `#[pkg::req_data]` element and an inner `#[pkg::res_data]` element. 8 | --> tests/fail/absent_req_or_res.rs:6:5 9 | | 10 | 6 | mod b { 11 | | ^ 12 | 13 | error: The `#[pkg]` module must have an inner `#[pkg::req_data]` element and an inner `#[pkg::res_data]` element. 14 | --> tests/fail/absent_req_or_res.rs:14:5 15 | | 16 | 14 | mod c { 17 | | ^ 18 | 19 | error: aborting due to 3 previous errors 20 | 21 | -------------------------------------------------------------------------------- /.github/workflows/bencher.yaml: -------------------------------------------------------------------------------- 1 | name: Bencher 2 | 3 | on: 4 | schedule: 5 | - cron: "0 6 * * *" 6 | workflow_dispatch: 7 | 8 | jobs: 9 | benchmark_with_bencher: 10 | name: Continuous Benchmarking with Bencher 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v6 14 | - uses: bencherdev/bencher@main 15 | - name: Track base branch benchmarks with Bencher 16 | run: | 17 | bencher run \ 18 | --adapter rust_bench \ 19 | --branch main \ 20 | --err \ 21 | --project wtx \ 22 | --testbed ubuntu-latest \ 23 | --token "${{ secrets.BENCHER_API_TOKEN }}" \ 24 | "cargo bench --all-features" -------------------------------------------------------------------------------- /wtx-instances/generic-examples/http-client-pool.rs: -------------------------------------------------------------------------------- 1 | //! Fetches and prints the response body of a provided URI. 2 | //! 3 | //! Currently, only HTTP/2 is supported. 4 | 5 | extern crate tokio; 6 | extern crate wtx; 7 | extern crate wtx_instances; 8 | 9 | use wtx::{ 10 | http::{HttpClient, ReqBuilder, ReqResBuffer, client_pool::ClientPoolBuilder}, 11 | misc::{Uri, from_utf8_basic}, 12 | }; 13 | 14 | #[tokio::main] 15 | async fn main() -> wtx::Result<()> { 16 | let uri = Uri::new("SOME_URI"); 17 | let pool = ClientPoolBuilder::tokio(1).build(); 18 | let res = pool.send_req_recv_res(ReqResBuffer::empty(), ReqBuilder::get(uri.to_ref())).await?; 19 | println!("{}", from_utf8_basic(&res.rrd.body)?); 20 | Ok(()) 21 | } 22 | -------------------------------------------------------------------------------- /wtx/src/http/session.rs: -------------------------------------------------------------------------------- 1 | mod session_error; 2 | mod session_manager; 3 | mod session_manager_builder; 4 | #[cfg(feature = "http-server-framework")] 5 | mod session_middleware; 6 | mod session_state; 7 | mod session_store; 8 | 9 | pub use session_error::SessionError; 10 | pub use session_manager::*; 11 | pub use session_manager_builder::SessionManagerBuilder; 12 | #[cfg(feature = "http-server-framework")] 13 | pub use session_middleware::SessionMiddleware; 14 | pub use session_state::SessionState; 15 | pub use session_store::SessionStore; 16 | 17 | type SessionCsrf = crate::collection::ArrayStringU8<32>; 18 | type SessionKey = crate::collection::ArrayStringU8<32>; 19 | type SessionSecret = crate::collection::ArrayStringU8<32>; 20 | -------------------------------------------------------------------------------- /wtx-macros-tests/tests/pass/df_builder_with_req_lf.rs: -------------------------------------------------------------------------------- 1 | //! Any request with lifetimes and custom data methods must have lifetimes that match 2 | //! both request and method signatures. 3 | 4 | wtx::create_packages_aux_wrapper!(); 5 | 6 | type Api = (); 7 | 8 | #[wtx_macros::pkg(data_format(json), id(super::Api), transport(http))] 9 | mod pkg { 10 | #[pkg::aux] 11 | impl super::PkgsAux<(), (), ()> { 12 | #[pkg::aux_data] 13 | fn foo_data<'any>(&mut self, param: &'any ()) -> wtx::Result> { 14 | Ok(param) 15 | } 16 | } 17 | 18 | #[pkg::req_data] 19 | pub(crate) type FooReq<'any> = &'any (); 20 | 21 | #[pkg::res_data] 22 | pub(crate) type FooRes = (); 23 | } 24 | 25 | fn main() { 26 | } 27 | -------------------------------------------------------------------------------- /wtx/src/database/client/mysql/protocol/stmt_close_req.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | database::client::mysql::{ 3 | command::Command, 4 | protocol::{Protocol, encode_wrapper_protocol::EncodeWrapperProtocol}, 5 | }, 6 | de::Encode, 7 | }; 8 | 9 | #[derive(Debug)] 10 | pub(crate) struct StmtCloseReq { 11 | pub(crate) statement: u32, 12 | } 13 | 14 | impl Encode> for StmtCloseReq 15 | where 16 | E: From, 17 | { 18 | #[inline] 19 | fn encode(&self, ew: &mut EncodeWrapperProtocol<'_>) -> Result<(), E> { 20 | let array = [&[Command::ComStmtClose.into()][..], &self.statement.to_le_bytes()]; 21 | let _ = ew.encode_buffer.extend_from_copyable_slices(array)?; 22 | Ok(()) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /wtx-macros-tests/Cargo.toml: -------------------------------------------------------------------------------- 1 | [dependencies] 2 | serde = { default-features = false, features = ["alloc", "derive"], optional = true, version = "1.0" } 3 | tokio = { default-features = false, features = ["macros", "net", "rt-multi-thread"], version = "1.0" } 4 | ui_test = { default-features = false, features = ["rustc"], version = "0.30" } 5 | wtx = { default-features = false, features = ["client-api-framework", "http", "http-client-pool", "postgres", "serde_json", "tokio", "web-socket-handshake"], path = "../wtx" } 6 | wtx-macros = { default-features = false, path = "../wtx-macros" } 7 | 8 | [package] 9 | edition = "2024" 10 | name = "wtx-macros-tests" 11 | publish = false 12 | rust-version = "1.89" 13 | version = "0.0.0" 14 | 15 | [workspace] -------------------------------------------------------------------------------- /wtx/src/misc/hints.rs: -------------------------------------------------------------------------------- 1 | /// Hints to the compiler that a callback is unlikely to occur. 2 | #[cold] 3 | #[inline(always)] 4 | #[track_caller] 5 | pub fn unlikely_cb(cb: F) -> T 6 | where 7 | F: FnOnce() -> T, 8 | { 9 | cb() 10 | } 11 | 12 | /// Hints to the compiler that an element is unlikely to occur. 13 | #[cold] 14 | #[inline(always)] 15 | #[track_caller] 16 | pub fn unlikely_elem(elem: T) -> T { 17 | elem 18 | } 19 | 20 | #[allow(clippy::panic, reason = "programming error that should be unreachable")] 21 | #[cold] 22 | #[inline(always)] 23 | #[track_caller] 24 | pub(crate) const fn _unlikely_unreachable() -> ! { 25 | panic!("Entered in a branch that should be impossible, which is likely a programming error"); 26 | } 27 | -------------------------------------------------------------------------------- /wtx-docs/src/calendar/README.md: -------------------------------------------------------------------------------- 1 | # Calendar 2 | 3 | Provides basic primitives to work with time-related operations. 4 | 5 | * `Date`: Proleptic Gregorian calendar. Can represent years from -32767 to 32766. 6 | 7 | * `DateTime`: ISO-8601 representation with timezones. 8 | 9 | * `Duration`: Time span in nanoseconds. Can be negative unlike `core::time::Duration`. 10 | 11 | * `Instant`: A specific point in time. Contains the underlying mechanism that provides a timestamp. 12 | 13 | * `Time` Clock time with nanosecond precision. 14 | 15 | Also supports arithmetic operations and flexible formatting. 16 | 17 | ## Example 18 | 19 | ```rust,edition2024,no_run 20 | {{#rustdoc_include ../../../wtx-instances/generic-examples/calendar.rs}} 21 | ``` 22 | -------------------------------------------------------------------------------- /wtx/src/calendar/time_zone.rs: -------------------------------------------------------------------------------- 1 | mod dyn_tz; 2 | mod local; 3 | mod utc; 4 | 5 | use crate::collection::ArrayStringU8; 6 | pub use dyn_tz::DynTz; 7 | pub use local::Local; 8 | pub use utc::Utc; 9 | 10 | /// Timezone 11 | pub trait TimeZone: Copy { 12 | /// If the instance is of a literal `Local` type. 13 | const IS_LOCAL: bool; 14 | /// If the instance is of a literal `UTC` type. 15 | const IS_UTC: bool; 16 | 17 | /// Tries to create a new instance from the number of minutes. 18 | fn from_minutes(minutes: i16) -> crate::Result; 19 | 20 | /// ISO-8601 string representation 21 | fn iso8601(self) -> ArrayStringU8<6>; 22 | 23 | /// The number of minutes represented by this time zone 24 | fn minutes(&self) -> i16; 25 | } 26 | -------------------------------------------------------------------------------- /wtx-macros-tests/tests/fail/duplicated_local_pkg_attr.stderr: -------------------------------------------------------------------------------- 1 | error: It is not possible to have more than one `pkg` attribute in the same element. 2 | --> tests/fail/duplicated_local_pkg_attr.rs:3:3 3 | | 4 | 3 | #[pkg::aux] 5 | | ^^^^^^^^^^^ 6 | 7 | error: It is not possible to have more than one `pkg` attribute in the same element. 8 | --> tests/fail/duplicated_local_pkg_attr.rs:17:3 9 | | 10 | 17 | #[pkg::before_sending] 11 | | ^^^^^^^^^^^^^^^^^^^^^^ 12 | 13 | error: It is not possible to have more than one `pkg` attribute in the same element. 14 | --> tests/fail/duplicated_local_pkg_attr.rs:34:3 15 | | 16 | 34 | #[pkg::req_data] 17 | | ^^^^^^^^^^^^^^^^ 18 | 19 | error: aborting due to 3 previous errors 20 | 21 | -------------------------------------------------------------------------------- /wtx/src/stream/embassy_net.rs: -------------------------------------------------------------------------------- 1 | use crate::stream::{StreamReader, StreamWriter}; 2 | use embassy_net::tcp::TcpSocket; 3 | 4 | impl StreamReader for TcpSocket<'_> { 5 | #[inline] 6 | async fn read(&mut self, bytes: &mut [u8]) -> crate::Result { 7 | Ok((*self).read(bytes).await?) 8 | } 9 | } 10 | 11 | impl StreamWriter for TcpSocket<'_> { 12 | #[inline] 13 | async fn write_all(&mut self, mut bytes: &[u8]) -> crate::Result<()> { 14 | _local_write_all!(bytes, Self::write(self, bytes).await); 15 | Ok(()) 16 | } 17 | 18 | #[inline] 19 | async fn write_all_vectored(&mut self, bytes: &[&[u8]]) -> crate::Result<()> { 20 | for elem in bytes { 21 | self.write_all(elem).await?; 22 | } 23 | Ok(()) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /wtx/src/sync/fence.rs: -------------------------------------------------------------------------------- 1 | /// An atomic fence. 2 | /// 3 | /// Fences create synchronization between themselves and atomic operations or fences in other 4 | /// threads. To achieve this, a fence prevents the compiler and CPU from reordering certain types of 5 | /// memory operations around it. 6 | #[expect(clippy::disallowed_methods, reason = "this is the only placed")] 7 | #[inline] 8 | pub fn fence(order: core::sync::atomic::Ordering) { 9 | #[cfg(feature = "portable-atomic")] 10 | return portable_atomic::fence(order); 11 | #[cfg(all(feature = "loom", not(any(feature = "portable-atomic"))))] 12 | return loom::sync::atomic::fence(order); 13 | #[cfg(not(any(feature = "loom", feature = "portable-atomic")))] 14 | return core::sync::atomic::fence(order); 15 | } 16 | -------------------------------------------------------------------------------- /wtx-instances/database-examples/database-client-mysql.rs: -------------------------------------------------------------------------------- 1 | //! Demonstrates a MySQL query. 2 | 3 | extern crate tokio; 4 | extern crate wtx; 5 | extern crate wtx_instances; 6 | 7 | use wtx::database::{Executor, Record, Records}; 8 | use wtx_instances::executor_mysql; 9 | 10 | #[tokio::main] 11 | async fn main() -> wtx::Result<()> { 12 | let mut executor = executor_mysql("mysql://USER:PASSWORD@localhost/DATABASE").await?; 13 | let records = executor 14 | .execute_stmt_many("SELECT id, name FROM example", (), |_| Ok::<_, wtx::Error>(())) 15 | .await?; 16 | assert_eq!(records.get(0).as_ref().and_then(|record| record.decode("id").ok()), Some(1)); 17 | assert_eq!(records.get(1).as_ref().and_then(|record| record.decode("name").ok()), Some("two")); 18 | Ok(()) 19 | } 20 | -------------------------------------------------------------------------------- /.scripts/podman-start.sh: -------------------------------------------------------------------------------- 1 | podman run \ 2 | -d \ 3 | --name wtx_mysql \ 4 | -e MYSQL_DATABASE=wtx \ 5 | -e MYSQL_PASSWORD=wtx \ 6 | -e MYSQL_ROOT_HOST='%' \ 7 | -e MYSQL_ROOT_PASSWORD=wtx \ 8 | -e MYSQL_USER=wtx \ 9 | -p 3306:3306 \ 10 | -v .test-utils/my.cnf:/etc/mysql/my.cnf \ 11 | -v .test-utils/mysql.sh:/docker-entrypoint-initdb.d/setup.sh \ 12 | docker.io/library/mysql:9 13 | 14 | podman run \ 15 | --name wtx_postgres_scram \ 16 | -d \ 17 | -e POSTGRES_DB=wtx \ 18 | -e POSTGRES_PASSWORD=wtx \ 19 | -p 5432:5432 \ 20 | -v .test-utils/postgres.sh:/docker-entrypoint-initdb.d/setup.sh \ 21 | docker.io/library/postgres:18 22 | 23 | # Utils 24 | 25 | # podman exec -it wtx_postgres_scram psql -U wtx_scram -d wtx 26 | -------------------------------------------------------------------------------- /wtx-docs/src/environment-variables/README.md: -------------------------------------------------------------------------------- 1 | # Environment Variables 2 | 3 | `EnvVars` allows the insertion of environment variables into a custom structure where the name of the fields match the name of the variables. `.env` files are also supported but they should be restricted to development environments. 4 | 5 | The unsafe `std::env::set_var` function is not invoked due to concerns about concurrent access, therefore, direct usage of `std::env::var` is not recommended unless: 6 | 7 | 1. `EnvVars` is not used at all. 8 | 2. There are no `.env` files. 9 | 3. A specific variable is always originated from the current process. 10 | 11 | ## Example 12 | 13 | ```rust,edition2024,no_run 14 | {{#rustdoc_include ../../../wtx-instances/generic-examples/environment-variables.rs}} 15 | ``` 16 | 17 | -------------------------------------------------------------------------------- /wtx/src/misc/env_vars.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "std")] 2 | mod std; 3 | 4 | use alloc::string::String; 5 | 6 | /// Allows the interactive reading of environment variables. 7 | #[derive(Debug)] 8 | pub struct EnvVars(T); 9 | 10 | impl EnvVars 11 | where 12 | T: FromVars, 13 | { 14 | /// Constructs itself based on `vars`. 15 | /// 16 | /// Intended for debugging or tests. 17 | #[inline] 18 | pub fn from_iterator(vars: impl IntoIterator) -> crate::Result { 19 | Ok(Self(T::from_vars(vars)?)) 20 | } 21 | } 22 | 23 | /// Constructs itself using a set of `(key, value)` string pairs. 24 | pub trait FromVars: Sized { 25 | /// See [`FromVars`]. 26 | fn from_vars(vars: impl IntoIterator) -> crate::Result; 27 | } 28 | -------------------------------------------------------------------------------- /wtx/src/database/client/postgres/encode_wrapper.rs: -------------------------------------------------------------------------------- 1 | use crate::misc::{Lease, SuffixWriterFbvm}; 2 | 3 | /// Struct used for encoding elements in PostgreSQL. 4 | #[derive(Debug)] 5 | pub struct EncodeWrapper<'inner, 'outer> { 6 | buffer: &'outer mut SuffixWriterFbvm<'inner>, 7 | } 8 | 9 | impl<'inner, 'outer> EncodeWrapper<'inner, 'outer> { 10 | pub(crate) const fn new(buffer: &'outer mut SuffixWriterFbvm<'inner>) -> Self { 11 | Self { buffer } 12 | } 13 | 14 | /// Buffer used to encode messages that will be sent to PostgreSQL. 15 | pub const fn buffer(&mut self) -> &mut SuffixWriterFbvm<'inner> { 16 | self.buffer 17 | } 18 | } 19 | 20 | impl Lease<[u8]> for EncodeWrapper<'_, '_> { 21 | #[inline] 22 | fn lease(&self) -> &[u8] { 23 | self.buffer.curr_bytes() 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /wtx/src/database/value_ident.rs: -------------------------------------------------------------------------------- 1 | /// Value Identifier 2 | pub trait ValueIdent: Copy { 3 | /// Underlying index that represents this instance. 4 | fn idx(&self, input: &I) -> Option; 5 | } 6 | 7 | impl ValueIdent<()> for &str { 8 | #[inline] 9 | fn idx(&self, _: &()) -> Option { 10 | None 11 | } 12 | } 13 | 14 | impl ValueIdent for &T 15 | where 16 | T: ValueIdent, 17 | { 18 | #[inline] 19 | fn idx(&self, input: &I) -> Option { 20 | (**self).idx(input) 21 | } 22 | } 23 | 24 | impl ValueIdent for () { 25 | #[inline] 26 | fn idx(&self, _: &I) -> Option { 27 | None 28 | } 29 | } 30 | 31 | impl ValueIdent for usize { 32 | #[inline] 33 | fn idx(&self, _: &I) -> Option { 34 | Some(*self) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /wtx-macros/src/client_api_framework/pkg/fir.rs: -------------------------------------------------------------------------------- 1 | //! First Intermediate Representation (FIR) 2 | //! 3 | //! Performs basic input validation, extracts inner elements or modifies simple structures. 4 | 5 | #[macro_use] 6 | pub(crate) mod fir_custom_item_values; 7 | #[macro_use] 8 | pub(crate) mod fir_hook_item_values; 9 | 10 | pub(crate) mod fir_after_sending_item_values; 11 | pub(crate) mod fir_aux_field_attr; 12 | pub(crate) mod fir_aux_item_values; 13 | pub(crate) mod fir_before_sending_item_values; 14 | pub(crate) mod fir_custom_field_attr; 15 | pub(crate) mod fir_custom_field_field_attr; 16 | pub(crate) mod fir_item_attr; 17 | pub(crate) mod fir_items_values; 18 | pub(crate) mod fir_params_items_values; 19 | pub(crate) mod fir_pkg_attr; 20 | pub(crate) mod fir_req_item_values; 21 | pub(crate) mod fir_res_item_values; 22 | -------------------------------------------------------------------------------- /wtx/src/http/cookie/same_site.rs: -------------------------------------------------------------------------------- 1 | use core::fmt::{Display, Formatter}; 2 | 3 | /// Controls whether or not a cookie is sent with cross-site requests 4 | #[derive(Clone, Copy, Debug)] 5 | pub enum SameSite { 6 | /// Means that the is sent when a user is navigating to the origin site from an external site. 7 | Lax, 8 | /// Means that the browser sends the cookie with both cross-site and same-site requests. 9 | None, 10 | /// Means that the browser sends the cookie only for same-site requests 11 | Strict, 12 | } 13 | 14 | impl Display for SameSite { 15 | #[inline] 16 | fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { 17 | match *self { 18 | Self::Lax => write!(f, "Lax"), 19 | Self::None => write!(f, "None"), 20 | Self::Strict => write!(f, "Strict"), 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /wtx/src/stream/async_net.rs: -------------------------------------------------------------------------------- 1 | use crate::stream::{StreamReader, StreamWriter}; 2 | use async_net::TcpStream; 3 | use futures_lite::{AsyncReadExt, AsyncWriteExt}; 4 | 5 | impl StreamReader for TcpStream { 6 | #[inline] 7 | async fn read(&mut self, bytes: &mut [u8]) -> crate::Result { 8 | Ok(::read(self, bytes).await?) 9 | } 10 | } 11 | 12 | impl StreamWriter for TcpStream { 13 | #[inline] 14 | async fn write_all(&mut self, bytes: &[u8]) -> crate::Result<()> { 15 | ::write_all(self, bytes).await?; 16 | Ok(()) 17 | } 18 | 19 | #[inline] 20 | async fn write_all_vectored(&mut self, bytes: &[&[u8]]) -> crate::Result<()> { 21 | _local_write_all_vectored!(bytes, self, |io_slices| self.write_vectored(io_slices).await); 22 | Ok(()) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /wtx/src/calendar/time_zone/local.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | calendar::{CalendarError, TimeZone}, 3 | collection::{ArrayString, ArrayStringU8}, 4 | }; 5 | 6 | /// Local time. 7 | #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] 8 | pub struct Local; 9 | 10 | impl TimeZone for Local { 11 | const IS_LOCAL: bool = true; 12 | const IS_UTC: bool = false; 13 | 14 | #[inline] 15 | fn from_minutes(minutes: i16) -> crate::Result { 16 | if minutes != 0 { 17 | return Err( 18 | CalendarError::InvalidTimezoneSeconds { expected: None, received: minutes }.into(), 19 | ); 20 | } 21 | Ok(Self) 22 | } 23 | 24 | #[inline] 25 | fn iso8601(self) -> ArrayStringU8<6> { 26 | ArrayString::new() 27 | } 28 | 29 | #[inline] 30 | fn minutes(&self) -> i16 { 31 | 0 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /wtx/src/database/client/postgres/tys/arguments.rs: -------------------------------------------------------------------------------- 1 | use core::fmt::{Arguments, Write}; 2 | 3 | use crate::{ 4 | database::{ 5 | Typed, 6 | client::postgres::{EncodeWrapper, Postgres, Ty}, 7 | }, 8 | de::Encode, 9 | }; 10 | 11 | impl Encode> for Arguments<'_> 12 | where 13 | E: From, 14 | { 15 | #[inline] 16 | fn encode(&self, ew: &mut EncodeWrapper<'_, '_>) -> Result<(), E> { 17 | ew.buffer().write_fmt(*self).map_err(crate::Error::from)?; 18 | Ok(()) 19 | } 20 | } 21 | impl Typed> for Arguments<'_> 22 | where 23 | E: From, 24 | { 25 | #[inline] 26 | fn runtime_ty(&self) -> Option { 27 | >>::static_ty() 28 | } 29 | 30 | #[inline] 31 | fn static_ty() -> Option { 32 | Some(Ty::Text) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /wtx/src/rng/from_rng.rs: -------------------------------------------------------------------------------- 1 | use crate::{misc::Usize, rng::Rng}; 2 | 3 | /// Allows the creation of random instances. 4 | pub trait FromRng 5 | where 6 | RNG: Rng, 7 | { 8 | /// Creates a new instance based on `rng`. 9 | fn from_rng(rng: &mut RNG) -> Self; 10 | } 11 | 12 | impl FromRng for u8 13 | where 14 | RNG: Rng, 15 | { 16 | #[inline] 17 | fn from_rng(rng: &mut RNG) -> Self { 18 | rng.u8() 19 | } 20 | } 21 | 22 | impl FromRng for usize 23 | where 24 | RNG: Rng, 25 | { 26 | #[inline] 27 | fn from_rng(rng: &mut RNG) -> Self { 28 | #[cfg(target_pointer_width = "64")] 29 | return Usize::from_u64(u64::from_be_bytes(rng.u8_8())).into_usize(); 30 | #[cfg(not(target_pointer_width = "64"))] 31 | return Usize::from_u32(u32::from_be_bytes(rng.u8_4())).into_usize(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /wtx/src/sync/ref_counter.rs: -------------------------------------------------------------------------------- 1 | use crate::sync::Arc; 2 | use alloc::rc::Rc; 3 | use core::ops::Deref; 4 | 5 | /// Reference Counter 6 | /// 7 | /// Stores the number of references, pointers, or handles to a resource, such as an object, a 8 | /// block of memory, disk space and others. 9 | pub trait RefCounter: Clone + Deref { 10 | /// Item behind this counter. 11 | type Item; 12 | 13 | /// Generic way to build a reference counter. 14 | fn new(elem: Self::Item) -> Self; 15 | } 16 | 17 | impl RefCounter for Arc { 18 | type Item = T; 19 | 20 | #[inline] 21 | fn new(elem: Self::Item) -> Self { 22 | Arc::new(elem) 23 | } 24 | } 25 | 26 | impl RefCounter for Rc { 27 | type Item = T; 28 | 29 | #[inline] 30 | fn new(elem: Self::Item) -> Self { 31 | Rc::new(elem) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /wtx/src/database/client/mysql/protocol/lenenc_content.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | database::client::mysql::{ 3 | MysqlError, 4 | protocol::{Protocol, decode_wrapper_protocol::DecodeWrapperProtocol, lenenc::Lenenc}, 5 | }, 6 | de::Decode, 7 | misc::Usize, 8 | }; 9 | 10 | pub(crate) struct LenencContent<'bytes>(pub(crate) &'bytes [u8]); 11 | 12 | impl<'de, DO, E> Decode<'de, Protocol> for LenencContent<'de> 13 | where 14 | E: From, 15 | { 16 | #[inline] 17 | fn decode(dw: &mut DecodeWrapperProtocol<'de, '_, DO>) -> Result { 18 | let len = Lenenc::decode(dw)?; 19 | let Some((lhs, rhs)) = dw.bytes.split_at_checked(*Usize::from(len.0)) else { 20 | return Err(E::from(MysqlError::InvalidLenencContentBytes.into())); 21 | }; 22 | *dw.bytes = rhs; 23 | Ok(Self(lhs)) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /wtx/src/pool.rs: -------------------------------------------------------------------------------- 1 | //! Pool Manager 2 | 3 | mod resource_manager; 4 | #[cfg(feature = "std")] 5 | mod simple_pool; 6 | 7 | #[cfg(feature = "postgres")] 8 | pub use resource_manager::database::PostgresRM; 9 | pub use resource_manager::{ResourceManager, SimpleRM}; 10 | #[cfg(feature = "std")] 11 | pub use simple_pool::*; 12 | 13 | /// Manages HTTP/2 resources for clients and servers. 14 | #[cfg(feature = "http2")] 15 | pub type Http2BufferRM = SimpleRM crate::Result>; 16 | /// Manages resources for HTTP2 requests and responses. 17 | #[cfg(feature = "http2")] 18 | pub type StreamBufferRM = SimpleRM crate::Result>; 19 | /// Manages WebSocket resources. 20 | #[cfg(feature = "web-socket")] 21 | pub type WebSocketRM = SimpleRM crate::Result>; 22 | -------------------------------------------------------------------------------- /wtx/src/database/schema_manager/integration_tests/schema/without_schema.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | collection::Vector, 3 | database::{ 4 | Database, Identifier, 5 | schema_manager::{ 6 | Commands, DbMigration, MigrationStatus, SchemaManagement, integration_tests::AuxTestParams, 7 | }, 8 | }, 9 | }; 10 | use alloc::string::String; 11 | 12 | pub(crate) async fn _migrate_works( 13 | (buffer_cmd, _, _, _): ( 14 | &mut String, 15 | &mut Vector, 16 | &mut Vector, 17 | &mut Vector, 18 | ), 19 | c: &mut Commands, 20 | aux: AuxTestParams, 21 | ) where 22 | DB: Database, 23 | E: SchemaManagement, 24 | { 25 | crate::database::schema_manager::integration_tests::schema::migrate_works(buffer_cmd, c, aux, 6) 26 | .await 27 | } 28 | -------------------------------------------------------------------------------- /wtx/src/web_socket/compression/deflate_config.rs: -------------------------------------------------------------------------------- 1 | use crate::web_socket::compression::{CompressionLevel, WindowBits}; 2 | 3 | /// Configurations for the `permessage-deflate` extension from the IETF RFC 7692 4 | #[derive(Clone, Copy, Debug)] 5 | pub struct DeflateConfig { 6 | /// LZ77 sliding window size for the client. 7 | pub client_max_window_bits: WindowBits, 8 | /// Compression level. 9 | pub compression_level: CompressionLevel, 10 | /// LZ77 sliding window size for the server. 11 | pub server_max_window_bits: WindowBits, 12 | } 13 | 14 | impl Default for DeflateConfig { 15 | #[inline] 16 | fn default() -> Self { 17 | DeflateConfig { 18 | client_max_window_bits: WindowBits::Twelve, 19 | compression_level: CompressionLevel::default(), 20 | server_max_window_bits: WindowBits::Twelve, 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /wtx/src/client_api_framework/misc/from_bytes.rs: -------------------------------------------------------------------------------- 1 | use crate::misc::from_utf8_basic; 2 | use alloc::{string::String, vec::Vec}; 3 | 4 | /// This trait only exists because of the lack of `impl TryFrom<&[u8]> for String` but such 5 | /// implementation probably will never be a thing. 6 | pub trait FromBytes { 7 | /// Creates itself from a sequence of bytes. 8 | fn from_bytes(bytes: &[u8]) -> crate::Result 9 | where 10 | Self: Sized; 11 | } 12 | 13 | impl FromBytes for String { 14 | #[inline] 15 | fn from_bytes(bytes: &[u8]) -> crate::Result 16 | where 17 | Self: Sized, 18 | { 19 | Ok(from_utf8_basic(bytes)?.into()) 20 | } 21 | } 22 | 23 | impl FromBytes for Vec { 24 | #[inline] 25 | fn from_bytes(bytes: &[u8]) -> crate::Result 26 | where 27 | Self: Sized, 28 | { 29 | Ok(bytes.into()) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /.scripts/autobahn-fuzzingserver.sh: -------------------------------------------------------------------------------- 1 | set -euxo pipefail 2 | 3 | ARG=${1:-""} 4 | if [ "$ARG" != "ci" ]; then 5 | trap "trap - SIGTERM && kill -- -$$" SIGINT SIGTERM EXIT 6 | fi; 7 | 8 | cargo build --bin autobahn-client --features autobahn-client --release 9 | mkdir -p .scripts/autobahn/reports/fuzzingserver 10 | podman run \ 11 | -d \ 12 | -p 9080:9080 \ 13 | -v .scripts/autobahn/fuzzingserver-min.json:/fuzzingserver.json:ro \ 14 | -v .scripts/autobahn:/autobahn \ 15 | --name fuzzingserver \ 16 | --net=host \ 17 | crossbario/autobahn-testsuite:25.10.1 wstest -m fuzzingserver -s fuzzingserver.json 18 | sleep 5 19 | cargo run --bin autobahn-client --features autobahn-client --release 20 | podman rm --force --ignore fuzzingserver 21 | 22 | if [ $(grep -ci "failed" .scripts/autobahn/reports/fuzzingserver/index.json) -gt 0 ] 23 | then 24 | exit 1 25 | fi 26 | -------------------------------------------------------------------------------- /.scripts/autobahn-fuzzingclient.sh: -------------------------------------------------------------------------------- 1 | set -euxo pipefail 2 | 3 | ARG=${1:-""} 4 | if [ "$ARG" != "ci" ]; then 5 | trap "trap - SIGTERM && kill -- -$$" SIGINT SIGTERM EXIT 6 | fi; 7 | 8 | cargo build --bin autobahn-server --features autobahn-server --release 9 | cargo run --bin autobahn-server --features autobahn-server --release & cargo_pid=$! 10 | sleep 1 11 | mkdir -p .scripts/autobahn/reports/fuzzingclient 12 | podman run \ 13 | -p 9070:9070 \ 14 | -v .scripts/autobahn/fuzzingclient-min.json:/fuzzingclient.json:ro \ 15 | -v .scripts/autobahn:/autobahn \ 16 | --name fuzzingclient \ 17 | --network host \ 18 | --rm \ 19 | crossbario/autobahn-testsuite:25.10.1 wstest -m fuzzingclient -s fuzzingclient.json 20 | kill -9 $cargo_pid 21 | 22 | if [ $(grep -ci "failed" .scripts/autobahn/reports/fuzzingclient/index.json) -gt 0 ] 23 | then 24 | exit 1 25 | fi 26 | 27 | -------------------------------------------------------------------------------- /wtx-instances/http-server-framework-examples/http-server-framework-cors.rs: -------------------------------------------------------------------------------- 1 | //! The `CorsMiddleware` middleware inserts permissive CORS headers in every response. 2 | 3 | use wtx::{ 4 | http::server_framework::{CorsMiddleware, Router, ServerFrameworkBuilder, get}, 5 | rng::{Xorshift64, simple_seed}, 6 | }; 7 | 8 | #[tokio::main] 9 | async fn main() -> wtx::Result<()> { 10 | let router = Router::new(wtx::paths!(("/hello", get(hello))), CorsMiddleware::permissive()?)?; 11 | ServerFrameworkBuilder::new(Xorshift64::from(simple_seed()), router) 12 | .without_aux() 13 | .tokio( 14 | "0.0.0.0:9000", 15 | |error: wtx::Error| eprintln!("{error:?}"), 16 | |_| Ok(()), 17 | |_| Ok(()), 18 | |error| eprintln!("{error}"), 19 | ) 20 | .await?; 21 | Ok(()) 22 | } 23 | 24 | async fn hello() -> &'static str { 25 | "Hello" 26 | } 27 | -------------------------------------------------------------------------------- /wtx/src/de/format/borsh.rs: -------------------------------------------------------------------------------- 1 | use crate::misc::{Lease, LeaseMut}; 2 | 3 | /// Type that indicates the usage of the `borsh` dependency. 4 | #[derive(Debug, Default)] 5 | pub struct Borsh; 6 | 7 | impl Lease for Borsh { 8 | #[inline] 9 | fn lease(&self) -> &Borsh { 10 | self 11 | } 12 | } 13 | 14 | impl LeaseMut for Borsh { 15 | #[inline] 16 | fn lease_mut(&mut self) -> &mut Borsh { 17 | self 18 | } 19 | } 20 | 21 | #[cfg(all(feature = "client-api-framework", test))] 22 | mod tests { 23 | _create_dnsn_test!( 24 | borsh, 25 | (VerbatimEncoder, VerbatimDecoder), 26 | Borsh as Borsh, 27 | ([3, 0, 0, 0, 102, 111, 111][..].into(), [3, 0, 0, 0, 98, 97, 114][..].into()), 28 | ( 29 | VerbatimEncoder { data: _Foo { foo: "foo" } }, 30 | VerbatimDecoder { data: _Bar { bar: "bar".into() } } 31 | ), 32 | ); 33 | } 34 | -------------------------------------------------------------------------------- /wtx/src/web_socket/compression/window_bits.rs: -------------------------------------------------------------------------------- 1 | create_enum! { 2 | /// LZ77 sliding window size for the `permessage-deflate` extension from the IETF RFC 7692. 3 | #[derive(Clone, Copy, Debug, Default, Eq, Ord, PartialEq, PartialOrd)] 4 | pub enum WindowBits { 5 | /// Eight 6 | Eight = (8), 7 | /// Nine 8 | Nine = (9), 9 | /// Ten 10 | Ten = (10), 11 | /// Eleven 12 | #[default] 13 | Eleven = (11), 14 | /// Twelve 15 | Twelve = (12), 16 | /// Thirteen 17 | Thirteen = (13), 18 | /// Fourteen 19 | Fourteen = (14), 20 | /// Fifteen 21 | Fifteen = (15), 22 | } 23 | } 24 | 25 | impl WindowBits { 26 | /// Instance that represents the minimum allowed value. 27 | pub const MIN: Self = Self::Eight; 28 | /// Instance that represents the maximum allowed value. 29 | pub const MAX: Self = Self::Fifteen; 30 | } 31 | -------------------------------------------------------------------------------- /wtx-macros/Cargo.toml: -------------------------------------------------------------------------------- 1 | [dependencies] 2 | proc-macro2 = { default-features = false, version = "1.0" } 3 | quote = { default-features = false, features = ["proc-macro"], version = "1.0" } 4 | syn = { default-features = false, features = ["derive", "extra-traits", "full", "parsing", "printing", "proc-macro"], version = "2.0" } 5 | 6 | [features] 7 | default = [] 8 | std = [] 9 | 10 | [lib] 11 | proc-macro = true 12 | 13 | [package] 14 | categories = ["asynchronous", "data-structures", "network-programming"] 15 | description = "Procedural macros for wtx" 16 | edition = "2024" 17 | exclude = ["tests"] 18 | keywords = ["api", "client", "io", "network"] 19 | license = "MPL-2.0" 20 | name = "wtx-macros" 21 | readme = "README.md" 22 | repository = "https://github.com/c410-f3r/wtx" 23 | rust-version = "1.89" 24 | version = "0.6.2" 25 | 26 | [package.metadata.docs.rs] 27 | all-features = true 28 | -------------------------------------------------------------------------------- /wtx/src/misc/span.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug)] 2 | pub(crate) struct Entered<'span> { 3 | #[cfg(feature = "tracing")] 4 | _elem: tracing::span::Entered<'span>, 5 | #[cfg(not(feature = "tracing"))] 6 | _elem: &'span (), 7 | } 8 | 9 | #[derive(Clone, Debug)] 10 | pub(crate) struct Span { 11 | #[cfg(feature = "tracing")] 12 | _elem: tracing::span::Span, 13 | #[cfg(not(feature = "tracing"))] 14 | _elem: (), 15 | } 16 | 17 | impl Span { 18 | pub(crate) const fn new( 19 | #[cfg(feature = "tracing")] _elem: tracing::span::Span, 20 | #[cfg(not(feature = "tracing"))] _elem: (), 21 | ) -> Self { 22 | Self { _elem } 23 | } 24 | 25 | pub(crate) fn enter(&self) -> Entered<'_> { 26 | Entered { 27 | #[cfg(feature = "tracing")] 28 | _elem: self._elem.enter(), 29 | #[cfg(not(feature = "tracing"))] 30 | _elem: &self._elem, 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /wtx-macros-tests/tests/fail/duplicated_local_pkg_attr.rs: -------------------------------------------------------------------------------- 1 | #[wtx_macros::pkg(data_format(json), id(FooId))] 2 | mod pkg { 3 | #[pkg::aux] 4 | #[pkg::aux] 5 | impl Foo {} 6 | 7 | #[derive(Debug)] 8 | #[pkg::req_data] 9 | pub struct Req; 10 | 11 | #[pkg::res_data] 12 | struct Res; 13 | } 14 | 15 | #[wtx_macros::pkg(data_format(json), id(FooId))] 16 | mod pkg { 17 | #[pkg::before_sending] 18 | #[pkg::before_sending] 19 | async fn before_sending() -> wtx::Result<()> { 20 | Ok(()) 21 | } 22 | 23 | #[derive(Debug)] 24 | #[pkg::req_data] 25 | pub struct Req; 26 | 27 | #[pkg::res_data] 28 | struct Res; 29 | } 30 | 31 | #[wtx_macros::pkg(data_format(json), id(FooId))] 32 | mod pkg { 33 | #[derive(Debug)] 34 | #[pkg::req_data] 35 | #[pkg::req_data] 36 | pub struct Req; 37 | 38 | #[pkg::res_data] 39 | struct Res; 40 | } 41 | 42 | fn main() { 43 | } 44 | -------------------------------------------------------------------------------- /wtx/src/calendar/time_zone/utc.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | calendar::{CalendarError, TimeZone}, 3 | collection::{ArrayString, ArrayStringU8}, 4 | }; 5 | 6 | /// Universal Time Coordinated (UTC) 7 | #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] 8 | pub struct Utc; 9 | 10 | impl TimeZone for Utc { 11 | const IS_LOCAL: bool = false; 12 | const IS_UTC: bool = true; 13 | 14 | #[inline] 15 | fn from_minutes(minutes: i16) -> crate::Result { 16 | if minutes != 0 { 17 | return Err( 18 | CalendarError::InvalidTimezoneSeconds { expected: Some(0), received: minutes }.into(), 19 | ); 20 | } 21 | Ok(Self) 22 | } 23 | 24 | #[inline] 25 | fn iso8601(self) -> ArrayStringU8<6> { 26 | let mut str = ArrayString::new(); 27 | let _rslt = str.push('Z'); 28 | str 29 | } 30 | 31 | #[inline] 32 | fn minutes(&self) -> i16 { 33 | 0 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /wtx-instances/generic-examples/secrets.rs: -------------------------------------------------------------------------------- 1 | //! Long lived secret 2 | 3 | extern crate wtx; 4 | 5 | use crate::wtx::rng::SeedableRng; 6 | use std::{env, sync::OnceLock}; 7 | use wtx::{ 8 | collection::Vector, 9 | misc::{Secret, SensitiveBytes}, 10 | rng::ChaCha20, 11 | }; 12 | 13 | static SECRET: OnceLock = OnceLock::new(); 14 | 15 | fn main() -> wtx::Result<()> { 16 | let data = env::args().nth(1).ok_or(wtx::Error::Generic(Box::new("No data".into())))?; 17 | let mut rng = ChaCha20::from_os()?; 18 | let secret = Secret::new(SensitiveBytes::new_locked(data.into_bytes().as_mut())?, &mut rng)?; 19 | let _rslt = SECRET.set(secret); 20 | std::thread::spawn(|| { 21 | let mut buffer = Vector::new(); 22 | SECRET.wait().peek(&mut buffer, |_data| { 23 | // Sign documents, pass API keys, etc... 24 | })?; 25 | wtx::Result::Ok(()) 26 | }) 27 | .join()??; 28 | Ok(()) 29 | } 30 | -------------------------------------------------------------------------------- /wtx/src/http/session/session_state.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | calendar::{DateTime, Utc}, 3 | http::session::{SessionCsrf, SessionKey}, 4 | }; 5 | 6 | /// Data that is saved in the corresponding store. 7 | #[derive(Clone, Copy, Debug, PartialEq, serde::Deserialize, serde::Serialize)] 8 | pub struct SessionState { 9 | /// Custom state 10 | pub custom_state: CS, 11 | /// Cookie expiration 12 | pub expires_at: Option>, 13 | /// CSRF token 14 | pub session_csrf: SessionCsrf, 15 | /// Identifier 16 | pub session_key: SessionKey, 17 | } 18 | 19 | impl SessionState { 20 | /// Constructor shortcut 21 | #[inline] 22 | pub const fn new( 23 | custom_state: CS, 24 | expires_at: Option>, 25 | session_csrf: SessionCsrf, 26 | session_key: SessionKey, 27 | ) -> Self { 28 | Self { custom_state, expires_at, session_csrf, session_key } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /.scripts/autobahn-fuzzingserver-concurrent.sh: -------------------------------------------------------------------------------- 1 | set -euxo pipefail 2 | 3 | ARG=${1:-""} 4 | if [ "$ARG" != "ci" ]; then 5 | trap "trap - SIGTERM && kill -- -$$" SIGINT SIGTERM EXIT 6 | fi; 7 | 8 | cargo build --bin autobahn-client-concurrent --features autobahn-client-concurrent --release 9 | mkdir -p .scripts/autobahn/reports/fuzzingserver 10 | podman run \ 11 | -d \ 12 | -p 9080:9080 \ 13 | -v .scripts/autobahn/fuzzingserver-min.json:/fuzzingserver.json:ro \ 14 | -v .scripts/autobahn:/autobahn \ 15 | --name fuzzingserver \ 16 | --net=host \ 17 | crossbario/autobahn-testsuite:25.10.1 wstest -m fuzzingserver -s fuzzingserver.json 18 | sleep 5 19 | cargo run --bin autobahn-client-concurrent --features autobahn-client-concurrent --release 20 | podman rm --force --ignore fuzzingserver 21 | 22 | if [ $(grep -ci "failed" .scripts/autobahn/reports/fuzzingserver/index.json) -gt 0 ] 23 | then 24 | exit 1 25 | fi 26 | -------------------------------------------------------------------------------- /wtx-docs/src/SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | - [Introduction](README.md) 4 | - [Calendar](calendar/README.md) 5 | - [Client API Framework](client-api-framework/README.md) 6 | - [Database Client](database-client/README.md) 7 | - [Encrypted Connections](database-client/encrypted-connections.md) 8 | - [Database Schema Manager](database-schema-manager/README.md) 9 | - [Environment Variables](environment-variables/README.md) 10 | - [Error Handling](error-handling/README.md) 11 | - [Executor](executor/README.md) 12 | - [gRPC](grpc/README.md) 13 | - [HTTP Client Pool](http-client-pool/README.md) 14 | - [HTTP Server Framework](http-server-framework/README.md) 15 | - [HTTP/2](http2/README.md) 16 | - [Internal Development](internal-development/README.md) 17 | - [Secrets](secrets/README.md) 18 | - [UI Tools](ui-tools/README.md) 19 | - [WebSocket](web-socket/README.md) 20 | - [WebSocket over HTTP/2](web-socket-over-http2/README.md) 21 | -------------------------------------------------------------------------------- /wtx/src/de/format.rs: -------------------------------------------------------------------------------- 1 | //! Abstracts different serialization/deserialization frameworks to enhance de-coupling. 2 | 3 | #[cfg(all(feature = "client-api-framework", test))] 4 | #[macro_use] 5 | mod tests; 6 | 7 | #[cfg(feature = "borsh")] 8 | mod borsh; 9 | mod de; 10 | mod decode_wrapper; 11 | mod encode_wrapper; 12 | mod hex; 13 | #[cfg(feature = "quick-protobuf")] 14 | mod quick_protobuf; 15 | #[cfg(feature = "serde_json")] 16 | mod serde_json; 17 | #[cfg(feature = "serde_urlencoded")] 18 | mod urlencoded; 19 | 20 | #[cfg(feature = "borsh")] 21 | pub use self::borsh::*; 22 | #[cfg(feature = "quick-protobuf")] 23 | pub use self::quick_protobuf::*; 24 | #[cfg(feature = "serde_json")] 25 | pub use self::serde_json::*; 26 | pub use de::De; 27 | pub use decode_wrapper::DecodeWrapper; 28 | pub use encode_wrapper::EncodeWrapper; 29 | pub use hex::Hex; 30 | #[cfg(feature = "serde_urlencoded")] 31 | pub use urlencoded::Urlencoded; 32 | -------------------------------------------------------------------------------- /wtx/src/http/server_framework/middleware.rs: -------------------------------------------------------------------------------- 1 | use crate::http::{ReqResBuffer, Request, Response, StatusCode}; 2 | use core::ops::ControlFlow; 3 | 4 | /// Request middleware 5 | pub trait Middleware 6 | where 7 | E: From, 8 | { 9 | /// Auxiliary structure 10 | type Aux; 11 | 12 | /// Auxiliary structure 13 | fn aux(&self) -> Self::Aux; 14 | 15 | /// Modifies or halts requests. 16 | fn req( 17 | &self, 18 | conn_aux: &mut CA, 19 | mw_aux: &mut Self::Aux, 20 | req: &mut Request, 21 | stream_aux: &mut SA, 22 | ) -> impl Future, E>>; 23 | 24 | /// Modifies or halts responses. 25 | fn res( 26 | &self, 27 | conn_aux: &mut CA, 28 | mw_aux: &mut Self::Aux, 29 | res: Response<&mut ReqResBuffer>, 30 | stream_aux: &mut SA, 31 | ) -> impl Future, E>>; 32 | } 33 | -------------------------------------------------------------------------------- /wtx-macros-tests/tests/pass/mutable_references.rs: -------------------------------------------------------------------------------- 1 | //! Uses mutable references to send packages 2 | 3 | wtx::create_packages_aux_wrapper!(); 4 | 5 | use wtx::client_api_framework::network::transport::SendingTransport; 6 | 7 | type Api = (); 8 | 9 | #[wtx_macros::pkg(data_format(json), id(super::Api), transport(stub))] 10 | mod pkg { 11 | use wtx::client_api_framework::network::transport::TransportParams; 12 | 13 | #[pkg::aux] 14 | impl super::PkgsAux where TP: TransportParams {} 15 | 16 | #[derive(Debug)] 17 | #[pkg::req_data] 18 | pub(crate) struct FooReq; 19 | 20 | #[pkg::res_data] 21 | pub(crate) type FooRes = (); 22 | } 23 | 24 | fn main() { 25 | let mut api = (); 26 | let drsr = (); 27 | let mut tp = (); 28 | let mut trans = (); 29 | let mut pkgs_aux = PkgsAux::from_minimum(&mut api, drsr, &mut tp); 30 | let _ = trans.send_pkg(&mut pkgs_aux.foo().build(), &mut pkgs_aux); 31 | } 32 | -------------------------------------------------------------------------------- /wtx/src/sync/cache_padded.rs: -------------------------------------------------------------------------------- 1 | use core::ops::{Deref, DerefMut}; 2 | 3 | /// Prevents false sharing by padding and aligning to the length of a cache line. 4 | #[cfg_attr( 5 | any(target_arch = "aarch64", target_arch = "powerpc64", target_arch = "x86_64",), 6 | repr(align(128)) 7 | )] 8 | #[cfg_attr( 9 | not(any(target_arch = "aarch64", target_arch = "powerpc64", target_arch = "x86_64",)), 10 | repr(align(64)) 11 | )] 12 | #[derive(Debug)] 13 | pub struct CachePadded( 14 | /// Element 15 | pub T, 16 | ); 17 | 18 | impl Deref for CachePadded { 19 | type Target = T; 20 | 21 | #[inline] 22 | fn deref(&self) -> &T { 23 | &self.0 24 | } 25 | } 26 | 27 | impl DerefMut for CachePadded { 28 | #[inline] 29 | fn deref_mut(&mut self) -> &mut T { 30 | &mut self.0 31 | } 32 | } 33 | 34 | impl From for CachePadded { 35 | #[inline] 36 | fn from(t: T) -> Self { 37 | CachePadded(t) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /wtx/src/stream/stream_with_tls.rs: -------------------------------------------------------------------------------- 1 | use crate::misc::Lease; 2 | 3 | /// Transport Layer Security 4 | pub trait StreamWithTls { 5 | /// Channel binding data defined in [RFC 5929]. 6 | /// 7 | /// [RFC 5929]: https://tools.ietf.org/html/rfc5929 8 | type TlsServerEndPoint: Lease<[u8]>; 9 | 10 | /// See `Self::TlsServerEndPoint`. 11 | fn tls_server_end_point(&self) -> crate::Result>; 12 | } 13 | 14 | impl StreamWithTls for () { 15 | type TlsServerEndPoint = [u8; 0]; 16 | 17 | #[inline] 18 | fn tls_server_end_point(&self) -> crate::Result> { 19 | Ok(None) 20 | } 21 | } 22 | 23 | impl StreamWithTls for &T 24 | where 25 | T: StreamWithTls, 26 | { 27 | type TlsServerEndPoint = T::TlsServerEndPoint; 28 | 29 | #[inline] 30 | fn tls_server_end_point(&self) -> crate::Result> { 31 | (*self).tls_server_end_point() 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /wtx/src/database/database_error.rs: -------------------------------------------------------------------------------- 1 | use alloc::boxed::Box; 2 | 3 | /// Database Error 4 | #[derive(Debug, PartialEq)] 5 | pub enum DatabaseError { 6 | /// The method `expand` of `StatementBuilder` must be called only once. 7 | InconsistentStatementBuilder, 8 | /// A "null" field received from the database was decoded as a non-nullable type or value. 9 | MissingFieldDataInDecoding(Box), 10 | /// Expected one record but got none. 11 | MissingSingleRecord, 12 | /// Received size differs from expected size. 13 | UnexpectedBufferSize { 14 | /// Expected 15 | expected: u32, 16 | /// Received 17 | received: u32, 18 | }, 19 | /// Expected no records but got at least one. 20 | UnexpectedRecords, 21 | /// Bytes don't represent expected type 22 | UnexpectedValueFromBytes { 23 | /// Expected 24 | expected: &'static str, 25 | }, 26 | /// Received a statement ID that is not present in the local cache. 27 | UnknownStatementId, 28 | } 29 | -------------------------------------------------------------------------------- /wtx/src/database/schema_manager/commands/multi.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | database::schema_manager::{ 3 | Commands, DEFAULT_CFG_FILE_NAME, SchemaManagement, misc::parse_root_toml, 4 | }, 5 | de::DEController, 6 | misc::find_file, 7 | }; 8 | use std::{env::current_dir, path::Path}; 9 | 10 | impl Commands 11 | where 12 | E: SchemaManagement, 13 | { 14 | /// Useful for DB tests. 15 | #[inline] 16 | pub async fn clear_migrate_and_seed( 17 | &mut self, 18 | ) -> Result<(), ::Error> { 19 | let mut buffer = current_dir().map_err(crate::Error::from)?; 20 | find_file(&mut buffer, Path::new(DEFAULT_CFG_FILE_NAME)).map_err(crate::Error::from)?; 21 | let (migration_groups, seeds) = parse_root_toml(&buffer)?; 22 | self.clear().await?; 23 | self.migrate_from_groups_paths(&migration_groups).await?; 24 | if let Some(elem) = seeds { 25 | self.seed_from_dir(&elem).await?; 26 | } 27 | Ok(()) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /wtx/src/sync/sync_mutex/no_std.rs: -------------------------------------------------------------------------------- 1 | use core::ops::{Deref, DerefMut}; 2 | 3 | #[derive(Debug)] 4 | pub(crate) struct NoStdMutex(T); 5 | 6 | impl NoStdMutex { 7 | pub(crate) const fn new(elem: T) -> Self { 8 | Self(elem) 9 | } 10 | 11 | pub(crate) fn lock(&self) -> NoStdMutexGuard<'_, T> { 12 | NoStdMutexGuard(&self.0) 13 | } 14 | 15 | pub(crate) fn try_lock(&self) -> Option> { 16 | None 17 | } 18 | } 19 | 20 | #[clippy::has_significant_drop] 21 | #[derive(Debug)] 22 | pub(crate) struct NoStdMutexGuard<'any, T>(&'any T); 23 | 24 | impl Deref for NoStdMutexGuard<'_, T> { 25 | type Target = T; 26 | 27 | #[inline] 28 | fn deref(&self) -> &T { 29 | &self.0 30 | } 31 | } 32 | 33 | impl DerefMut for NoStdMutexGuard<'_, T> { 34 | #[expect(clippy::panic, reason = "not implemented yet")] 35 | #[inline] 36 | fn deref_mut(&mut self) -> &mut T { 37 | panic!("Operation not supported yet"); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /wtx/src/database/records.rs: -------------------------------------------------------------------------------- 1 | use crate::database::Database; 2 | 3 | /// A collection of [`crate::database::Record`]. 4 | pub trait Records<'exec>: Default { 5 | /// See [Database]. 6 | type Database: Database; 7 | 8 | /// Tries to retrieve a record. 9 | fn get(&self, record_idx: usize) -> Option<::Record<'exec>>; 10 | 11 | /// Iterator of records. 12 | fn iter(&self) -> impl Iterator::Record<'exec>>; 13 | 14 | /// The number of records. 15 | fn len(&self) -> usize; 16 | } 17 | 18 | impl<'exec> Records<'exec> for () { 19 | type Database = (); 20 | 21 | #[inline] 22 | fn get(&self, _: usize) -> Option<::Record<'exec>> { 23 | None 24 | } 25 | 26 | #[inline] 27 | fn iter(&self) -> impl Iterator::Record<'exec>> { 28 | [].into_iter() 29 | } 30 | 31 | #[inline] 32 | fn len(&self) -> usize { 33 | 0 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /wtx/src/http/server_framework/verbatim_params.rs: -------------------------------------------------------------------------------- 1 | use crate::http::StatusCode; 2 | 3 | /// Does not modify the parameters of a request that will be used to form a response. Users 4 | /// should carefully handle incoming and outgoing data. 5 | #[derive(Clone, Copy, Debug)] 6 | pub struct VerbatimParams( 7 | /// Status code of the response 8 | pub StatusCode, 9 | ); 10 | 11 | impl Default for VerbatimParams { 12 | #[inline] 13 | fn default() -> Self { 14 | Self(StatusCode::Ok) 15 | } 16 | } 17 | 18 | #[cfg(feature = "http-server-framework")] 19 | mod http_server_framework { 20 | use crate::http::{ 21 | ReqResBuffer, Request, StatusCode, 22 | server_framework::{ResFinalizer, VerbatimParams}, 23 | }; 24 | 25 | impl ResFinalizer for VerbatimParams 26 | where 27 | E: From, 28 | { 29 | #[inline] 30 | fn finalize_response(self, _: &mut Request) -> Result { 31 | Ok(self.0) 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /wtx-macros/src/client_api_framework/pkg/fir/fir_custom_field_field_attr.rs: -------------------------------------------------------------------------------- 1 | use crate::client_api_framework::pkg::keywords; 2 | use proc_macro2::Ident; 3 | use syn::{ 4 | LitStr, Token, 5 | parse::{Parse, ParseStream}, 6 | }; 7 | 8 | #[derive(Debug)] 9 | pub(crate) struct FirCustomFieldFieldAttr { 10 | pub(crate) name: Ident, 11 | } 12 | 13 | impl Parse for FirCustomFieldFieldAttr { 14 | fn parse(input: ParseStream<'_>) -> syn::Result { 15 | let mut name = None; 16 | while !input.is_empty() { 17 | let lookahead = input.lookahead1(); 18 | if lookahead.peek(keywords::name) { 19 | let _ = input.parse::()?; 20 | let _ = input.parse::()?; 21 | let s = input.parse::()?; 22 | name = Some(Ident::new(&s.value(), s.span())); 23 | } else { 24 | return Err(lookahead.error()); 25 | } 26 | } 27 | Ok(Self { name: name.ok_or_else(|| crate::Error::BadField(input.span()))? }) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /wtx/src/http/cookie.rs: -------------------------------------------------------------------------------- 1 | mod cookie_error; 2 | #[cfg(feature = "http-session")] 3 | pub(crate) mod cookie_generic; 4 | #[cfg(all(feature = "http-server-framework", feature = "http-session"))] 5 | pub(crate) mod cookie_str; 6 | mod same_site; 7 | 8 | #[cfg(feature = "http-session")] 9 | use crate::calendar::CalendarToken; 10 | pub use cookie_error::CookieError; 11 | pub use same_site::SameSite; 12 | 13 | #[cfg(feature = "http-session")] 14 | static FMT1: &[CalendarToken] = &[ 15 | CalendarToken::AbbreviatedWeekdayName, 16 | CalendarToken::Comma, 17 | CalendarToken::Space, 18 | CalendarToken::TwoDigitDay, 19 | CalendarToken::Space, 20 | CalendarToken::AbbreviatedMonthName, 21 | CalendarToken::Space, 22 | CalendarToken::FourDigitYear, 23 | CalendarToken::Space, 24 | CalendarToken::TwoDigitHour, 25 | CalendarToken::Colon, 26 | CalendarToken::TwoDigitMinute, 27 | CalendarToken::Colon, 28 | CalendarToken::TwoDigitSecond, 29 | CalendarToken::Space, 30 | CalendarToken::Gmt, 31 | ]; 32 | -------------------------------------------------------------------------------- /wtx/src/misc/utf8_errors.rs: -------------------------------------------------------------------------------- 1 | use crate::misc::IncompleteUtf8Char; 2 | 3 | /// Extended error built upon [`StdUtf8Error`]. 4 | #[derive(Debug)] 5 | pub enum ExtUtf8Error { 6 | /// More bytes are needed to validate the string. 7 | Incomplete { 8 | /// See [`IncompleteUtf8Char`]. 9 | incomplete_ending_char: IncompleteUtf8Char, 10 | }, 11 | /// It is impossible to validate the string 12 | Invalid, 13 | } 14 | 15 | /// Basic string error that doesn't contain any information. 16 | #[derive(Debug)] 17 | pub struct BasicUtf8Error; 18 | 19 | impl From for crate::Error { 20 | #[inline] 21 | #[track_caller] 22 | fn from(_: BasicUtf8Error) -> Self { 23 | Self::InvalidUTF8 24 | } 25 | } 26 | 27 | /// Standard error that is similar to the error type of the standard library. 28 | #[derive(Debug)] 29 | pub struct StdUtf8Error { 30 | /// Error length 31 | pub error_len: Option, 32 | /// Starting index of mal-formatted bytes 33 | pub valid_up_to: usize, 34 | } 35 | -------------------------------------------------------------------------------- /wtx/src/rng/seedable_rng.rs: -------------------------------------------------------------------------------- 1 | use crate::{misc::LeaseMut, rng::Rng}; 2 | 3 | /// A random number generator that can be explicitly seeded. 4 | pub trait SeedableRng: Sized { 5 | /// Number used to construct instances 6 | type Seed: Clone + Default + LeaseMut<[u8]>; 7 | 8 | /// Creates a new instance based on the entropy provided by the OS. 9 | #[cfg(feature = "getrandom")] 10 | #[inline] 11 | fn from_os() -> crate::Result { 12 | let mut seed = Self::Seed::default(); 13 | getrandom::fill(seed.lease_mut())?; 14 | Self::from_seed(seed) 15 | } 16 | 17 | /// Creates a new instance based on another RNG. 18 | #[inline] 19 | fn from_rng(rng: &mut R) -> crate::Result 20 | where 21 | R: Rng, 22 | { 23 | let mut seed = Self::Seed::default(); 24 | rng.fill_slice(seed.lease_mut()); 25 | Self::from_seed(seed) 26 | } 27 | 28 | /// Creates a new instance based on the providede seed. 29 | fn from_seed(seed: Self::Seed) -> crate::Result; 30 | } 31 | -------------------------------------------------------------------------------- /wtx/src/sync.rs: -------------------------------------------------------------------------------- 1 | //! Synchronizing primitives 2 | //! 3 | //! Some of the `no_std` structures located in this module were copied from the 4 | //! project and modified to fit into `wtx`. On the 5 | //! other hand, some structures are just wrappers or facades of third-parties. 6 | 7 | mod arc; 8 | mod async_mutex; 9 | mod atomic_cell; 10 | mod atomic_waker; 11 | mod back_off; 12 | mod cache_padded; 13 | mod fence; 14 | mod mpmc; 15 | mod primitives; 16 | mod ref_counter; 17 | mod seq_lock; 18 | mod sync_mutex; 19 | 20 | pub use arc::Arc; 21 | pub use async_mutex::{AsyncMutex, AsyncMutexGuard, AsyncMutexGuardFuture}; 22 | pub use atomic_cell::AtomicCell; 23 | pub use atomic_waker::AtomicWaker; 24 | pub use back_off::Backoff; 25 | pub use cache_padded::CachePadded; 26 | pub use fence::fence; 27 | pub use mpmc::*; 28 | pub use primitives::*; 29 | pub use ref_counter::RefCounter; 30 | pub(crate) use seq_lock::SeqLock; 31 | pub use sync_mutex::{SyncMutex, SyncMutexGuard}; 32 | -------------------------------------------------------------------------------- /wtx-docs/src/web-socket-over-http2/README.md: -------------------------------------------------------------------------------- 1 | # WebSocket over HTTP/2 2 | 3 | At the current time only servers support the handshake procedure defined in [RFC8441](https://datatracker.ietf.org/doc/html/rfc8441). 4 | 5 | While HTTP/2 inherently supports full-duplex communication, web browsers typically don't expose this functionality directly to developers and that is why WebSocket tunneling over HTTP/2 is important. 6 | 7 | 1. Servers can efficiently handle multiple concurrent streams within a single TCP connection 8 | 2. Client applications can continue using existing WebSocket APIs without modification 9 | 10 | For this particular scenario the `no-masking` parameter defined in is also supported. 11 | 12 | To use this functionality, it is necessary to activate the `http2` and `web-socket` features. 13 | 14 | ## Example 15 | 16 | ```rust,2024,no_run 17 | {{#rustdoc_include ../../../wtx-instances/http2-examples/http2-server.rs}} 18 | ``` -------------------------------------------------------------------------------- /wtx/src/calendar/tracing_tree_timer.rs: -------------------------------------------------------------------------------- 1 | use crate::calendar::Instant; 2 | use core::time::Duration; 3 | use std::fmt::Write; 4 | use tracing_tree::time::FormatTime; 5 | 6 | /// Invokes the current time for logging purposes. 7 | #[derive(Debug)] 8 | pub struct TracingTreeTimer; 9 | 10 | impl FormatTime for TracingTreeTimer { 11 | #[inline] 12 | fn format_time(&self, w: &mut impl Write) -> core::fmt::Result { 13 | w.write_str(Instant::now_date_time(0).unwrap_or_default().trunc_to_sec().iso8601().as_str())?; 14 | Ok(()) 15 | } 16 | 17 | #[inline] 18 | fn style_timestamp(&self, _: bool, elapsed: Duration, w: &mut impl Write) -> std::fmt::Result { 19 | let millis = elapsed.as_millis(); 20 | let secs = elapsed.as_secs(); 21 | let (num, unit) = if millis < 1000 { 22 | (millis as _, "ms") 23 | } else if secs < 60 { 24 | (secs, "s ") 25 | } else { 26 | (secs / 60, "m ") 27 | }; 28 | w.write_fmt(format_args!("{num:>3}{unit}"))?; 29 | Ok(()) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /wtx/src/misc/poll_once.rs: -------------------------------------------------------------------------------- 1 | use core::{ 2 | fmt::{Debug, Formatter}, 3 | pin::Pin, 4 | task::{Context, Poll}, 5 | }; 6 | 7 | /// Polls a future once. 8 | #[must_use = "futures do nothing without .await calls"] 9 | pub struct PollOnce { 10 | fut: F, 11 | } 12 | 13 | impl PollOnce { 14 | /// New instance 15 | #[inline] 16 | pub const fn new(fut: F) -> Self { 17 | Self { fut } 18 | } 19 | } 20 | 21 | impl Debug for PollOnce { 22 | #[inline] 23 | fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { 24 | f.debug_struct("PollOnce").finish() 25 | } 26 | } 27 | 28 | impl Future for PollOnce 29 | where 30 | F: Future + Unpin, 31 | { 32 | type Output = Option; 33 | 34 | #[inline] 35 | fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { 36 | match Pin::new(&mut self.fut).poll(cx) { 37 | Poll::Ready(elem) => Poll::Ready(Some(elem)), 38 | Poll::Pending => Poll::Ready(None), 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /wtx/src/database/client/postgres/postgres_column_info.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | database::{ 3 | Identifier, 4 | client::{postgres::Ty, rdbms::column_info::ColumnInfo}, 5 | }, 6 | misc::Lease, 7 | }; 8 | 9 | #[derive(Clone, Debug, Eq, PartialEq)] 10 | pub(crate) struct PostgresColumnInfo { 11 | pub(crate) name: Identifier, 12 | pub(crate) ty: Ty, 13 | } 14 | 15 | impl PostgresColumnInfo { 16 | pub(crate) const fn new(name: Identifier, ty: Ty) -> Self { 17 | Self { name, ty } 18 | } 19 | } 20 | 21 | impl ColumnInfo for PostgresColumnInfo { 22 | type Ty = Ty; 23 | 24 | #[inline] 25 | fn name(&self) -> &str { 26 | &self.name 27 | } 28 | 29 | #[inline] 30 | fn ty(&self) -> &Self::Ty { 31 | &self.ty 32 | } 33 | } 34 | 35 | impl Lease for PostgresColumnInfo { 36 | #[inline] 37 | fn lease(&self) -> &str { 38 | &self.name 39 | } 40 | } 41 | 42 | impl Lease for PostgresColumnInfo { 43 | #[inline] 44 | fn lease(&self) -> &Ty { 45 | &self.ty 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /wtx/src/client_api_framework/network/transport_group.rs: -------------------------------------------------------------------------------- 1 | use core::fmt::{Display, Formatter}; 2 | 3 | /// It is possible to have one or more transports that send data using the same protocol. 4 | #[derive(Clone, Copy, Debug, Eq, PartialEq)] 5 | pub enum TransportGroup { 6 | /// Transport group depending outside of `wtx`. 7 | Custom(&'static str), 8 | /// Hypertext Transfer Protocol 9 | HTTP, 10 | /// Mock or dummy implementations 11 | Stub, 12 | /// WebSocket 13 | WebSocket, 14 | } 15 | 16 | impl From for &'static str { 17 | #[inline] 18 | fn from(from: TransportGroup) -> Self { 19 | match from { 20 | TransportGroup::Custom(elem) => elem, 21 | TransportGroup::HTTP => "HTTP", 22 | TransportGroup::Stub => "Stub", 23 | TransportGroup::WebSocket => "WebSocket", 24 | } 25 | } 26 | } 27 | 28 | impl Display for TransportGroup { 29 | #[inline] 30 | fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { 31 | f.write_str((*self).into()) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /wtx/src/database/schema_manager/fixed_sql_commands.rs: -------------------------------------------------------------------------------- 1 | // Many commands were retrieved from the flyway project (https://github.com/flyway) so credits to 2 | // the authors. 3 | 4 | macro_rules! _wtx_migration_columns { 5 | () => { 6 | "_wtx_migration_mg_uid INT NOT NULL, \ 7 | checksum VARCHAR(20) NOT NULL, \ 8 | name VARCHAR(128) NOT NULL, \ 9 | repeatability INTEGER NULL, \ 10 | uid INT NOT NULL, \ 11 | CONSTRAINT _wtx_migration_unq UNIQUE (uid, _wtx_migration_mg_uid)" 12 | }; 13 | } 14 | 15 | macro_rules! _wtx_migration_group_columns { 16 | () => { 17 | "uid INT NOT NULL PRIMARY KEY, \ 18 | name VARCHAR(128) NOT NULL, 19 | version INT NOT NULL" 20 | }; 21 | } 22 | 23 | macro_rules! _serial_id { 24 | () => { 25 | "id SERIAL NOT NULL PRIMARY KEY," 26 | }; 27 | } 28 | 29 | #[cfg(any(feature = "mysql", feature = "postgres"))] 30 | pub(crate) mod common; 31 | #[cfg(feature = "mysql")] 32 | pub(crate) mod mysql; 33 | #[cfg(feature = "postgres")] 34 | pub(crate) mod postgres; 35 | -------------------------------------------------------------------------------- /wtx/src/http/http_error.rs: -------------------------------------------------------------------------------- 1 | use crate::http::{KnownHeaderName, Method}; 2 | 3 | /// Http error 4 | #[derive(Debug)] 5 | pub enum HttpError { 6 | /// Generic request error 7 | BadRequest, 8 | /// Invalid HTTP/2 or HTTP/3 header 9 | InvalidHttp2pContent, 10 | /// Missing Header 11 | MissingHeader( 12 | /// Expected header name 13 | KnownHeaderName, 14 | ), 15 | /// Received request does not contain a method field 16 | MissingRequestMethod, 17 | /// Received response does not contain a status code field 18 | MissingResponseStatusCode, 19 | /// The URI doesn't have any placeholder 20 | MissingUriPlaceholder, 21 | /// Content-Type mismatch 22 | UnexpectedContentType, 23 | /// HTTP version does not match the expected method. 24 | UnexpectedHttpMethod { 25 | /// Expected method 26 | expected: Method, 27 | }, 28 | /// Unknown header name. 29 | UnknownHeaderNameFromBytes { 30 | /// Received length 31 | length: u32, 32 | }, 33 | /// URI mismatch 34 | UriMismatch, 35 | } 36 | -------------------------------------------------------------------------------- /wtx-fuzz/web_socket.rs: -------------------------------------------------------------------------------- 1 | //! WebSocket 2 | 3 | #![expect(clippy::unwrap_used, reason = "does not matter")] 4 | #![no_main] 5 | 6 | use wtx::{ 7 | collection::Vector, 8 | executor::Runtime, 9 | rng::{Xorshift64, simple_seed}, 10 | stream::BytesStream, 11 | web_socket::{Frame, OpCode, WebSocket, WebSocketBuffer, WebSocketPayloadOrigin}, 12 | }; 13 | 14 | libfuzzer_sys::fuzz_target!(|data: (OpCode, Vec)| { 15 | Runtime::new() 16 | .block_on(async move { 17 | let mut ws = WebSocket::<_, _, _, _, false>::new( 18 | (), 19 | false, 20 | Xorshift64::from(simple_seed()), 21 | BytesStream::default(), 22 | WebSocketBuffer::default(), 23 | ); 24 | ws.set_max_payload_len(u16::MAX.into()); 25 | let mut frame = Frame::new_fin(data.0, data.1); 26 | if ws.write_frame(&mut frame).await.is_err() { 27 | return; 28 | }; 29 | let _rslt = ws.read_frame(&mut Vector::new(), WebSocketPayloadOrigin::Adaptive).await; 30 | }) 31 | .unwrap(); 32 | }); 33 | -------------------------------------------------------------------------------- /wtx-instances/database-examples/database-client-postgres-batch.rs: -------------------------------------------------------------------------------- 1 | //! Sends multiple commands at once and awaits them. 2 | 3 | extern crate tokio; 4 | extern crate wtx; 5 | extern crate wtx_instances; 6 | 7 | use wtx::{ 8 | collection::ArrayVectorU8, 9 | database::{Record, Records}, 10 | misc::into_rslt, 11 | }; 12 | 13 | const COMMANDS: &[&str] = &["SELECT 0 = $1", "SELECT 1 = $1", "SELECT 2 = $1"]; 14 | 15 | #[tokio::main] 16 | async fn main() -> wtx::Result<()> { 17 | let uri = "postgres://USER:PASSWORD@localhost/DATABASE"; 18 | let mut executor = wtx_instances::executor_postgres(uri).await?; 19 | let mut batch = executor.batch(); 20 | let mut idx: u32 = 0; 21 | let mut records = ArrayVectorU8::<_, { COMMANDS.len() }>::new(); 22 | for cmd in COMMANDS { 23 | batch.stmt(cmd, (idx,))?; 24 | idx = idx.wrapping_add(1); 25 | } 26 | batch.flush(&mut records, |_| Ok(())).await?; 27 | for record in records { 28 | assert_eq!(into_rslt(record.get(0))?.decode::<_, bool>(0)?, true); 29 | } 30 | Ok(()) 31 | } 32 | -------------------------------------------------------------------------------- /wtx-macros/src/client_api_framework/pkg/sir/sir_pkg_attr.rs: -------------------------------------------------------------------------------- 1 | use crate::client_api_framework::{ 2 | pkg::{data_format::DataFormat, fir::fir_pkg_attr::FirPkgAttr}, 3 | transport_group::TransportGroup, 4 | }; 5 | use syn::Path; 6 | 7 | #[derive(Debug)] 8 | pub(crate) struct SirPkaAttr { 9 | pub(crate) data_formats: Vec, 10 | pub(crate) id: Path, 11 | pub(crate) transport_groups: Vec, 12 | } 13 | 14 | impl TryFrom for SirPkaAttr { 15 | type Error = crate::Error; 16 | 17 | #[inline] 18 | fn try_from(fea: FirPkgAttr) -> Result { 19 | let data_formats = 20 | fea.data_formats.iter().map(TryInto::try_into).collect::>>()?; 21 | if data_formats.is_empty() { 22 | return Err(crate::Error::MandatoryOuterAttrsAreNotPresent); 23 | } 24 | let transport_groups = 25 | fea.transports.iter().map(TryInto::try_into).collect::>()?; 26 | Ok(Self { data_formats, id: fea.id, transport_groups }) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /.scripts/internal-tests2.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | . "$(dirname "$0")/common.sh" --source-only 4 | 5 | # WTX 6 | 7 | $rt test-with-features wtx schema-manager-dev 8 | $rt test-with-features wtx serde 9 | $rt test-with-features wtx serde_json 10 | $rt test-with-features wtx sha1 11 | $rt test-with-features wtx sha2 12 | $rt test-with-features wtx simdutf8 13 | $rt test-with-features wtx std 14 | $rt test-with-features wtx tokio 15 | $rt test-with-features wtx tokio-rustls 16 | $rt test-with-features wtx tracing 17 | $rt test-with-features wtx uuid 18 | $rt test-with-features wtx web-socket 19 | $rt test-with-features wtx web-socket-handshake 20 | $rt test-with-features wtx webpki-roots 21 | 22 | # WTX Macros 23 | 24 | $rt test-generic wtx-macros 25 | 26 | # WTX UI 27 | 28 | $rt check-generic wtx-ui 29 | $rt test-with-features wtx-ui embed-migrations 30 | $rt test-with-features wtx-ui schema-manager 31 | $rt test-with-features wtx-ui schema-manager-dev 32 | $rt test-with-features wtx-ui http-client 33 | $rt test-with-features wtx-ui web-socket 34 | -------------------------------------------------------------------------------- /wtx-instances/build.rs: -------------------------------------------------------------------------------- 1 | //! Build 2 | 3 | #[expect(clippy::unwrap_used, reason = "illustration purposes")] 4 | #[cfg(feature = "grpc")] 5 | mod grpc { 6 | use pb_rs::{ConfigBuilder, types::FileDescriptor}; 7 | use std::{ 8 | fs::{DirBuilder, remove_dir_all}, 9 | path::Path, 10 | }; 11 | 12 | pub(crate) fn run() { 13 | let cmd = std::env::var("CARGO_MANIFEST_DIR").unwrap(); 14 | let in_dir = Path::new(&cmd).join("src"); 15 | let out_dir = Path::new(&std::env::var("OUT_DIR").unwrap()).join("protos"); 16 | if out_dir.exists() { 17 | remove_dir_all(&out_dir).unwrap(); 18 | } 19 | DirBuilder::new().create(&out_dir).unwrap(); 20 | FileDescriptor::run( 21 | &ConfigBuilder::new( 22 | &[Path::new(&cmd).join("src/grpc.proto").as_path()], 23 | None, 24 | Some(&out_dir.as_path()), 25 | &[in_dir.as_path()], 26 | ) 27 | .unwrap() 28 | .build(), 29 | ) 30 | .unwrap(); 31 | } 32 | } 33 | 34 | fn main() { 35 | #[cfg(feature = "grpc")] 36 | grpc::run(); 37 | } 38 | -------------------------------------------------------------------------------- /wtx-instances/http2-examples/http2-client.rs: -------------------------------------------------------------------------------- 1 | //! Fetches an URI using low-level HTTP/2 resources. 2 | 3 | extern crate tokio; 4 | extern crate wtx; 5 | extern crate wtx_instances; 6 | 7 | use tokio::net::TcpStream; 8 | use wtx::{ 9 | http::{HttpClient, ReqBuilder, ReqResBuffer}, 10 | http2::{Http2, Http2Buffer, Http2ErrorCode, Http2Params}, 11 | misc::{Uri, from_utf8_basic}, 12 | rng::{Xorshift64, simple_seed}, 13 | }; 14 | 15 | #[tokio::main] 16 | async fn main() -> wtx::Result<()> { 17 | let uri = Uri::new("SOME_URI"); 18 | let (frame_reader, http2) = Http2::connect( 19 | Http2Buffer::new(&mut Xorshift64::from(simple_seed())), 20 | Http2Params::default(), 21 | TcpStream::connect(uri.hostname_with_implied_port()).await?.into_split(), 22 | ) 23 | .await?; 24 | let _jh = tokio::spawn(frame_reader); 25 | let res = http2.send_req_recv_res(ReqResBuffer::empty(), ReqBuilder::get(uri.to_ref())).await?; 26 | println!("{}", from_utf8_basic(&res.rrd.body)?); 27 | http2.send_go_away(Http2ErrorCode::NoError).await; 28 | Ok(()) 29 | } 30 | -------------------------------------------------------------------------------- /wtx-macros/src/client_api_framework/pkg/fir/fir_aux_field_attr.rs: -------------------------------------------------------------------------------- 1 | use crate::client_api_framework::pkg::keywords; 2 | use syn::{ 3 | parse::{Parse, ParseStream}, 4 | spanned::Spanned as _, 5 | }; 6 | 7 | #[derive(Debug)] 8 | pub(crate) enum FirAuxFieldAttr { 9 | AuxData, 10 | AuxParams, 11 | } 12 | 13 | impl Parse for FirAuxFieldAttr { 14 | fn parse(input: ParseStream<'_>) -> syn::Result { 15 | let _ = input.parse::()?; 16 | let content; 17 | syn::bracketed!(content in input); 18 | let endpoint = content.parse::()?; 19 | let _ = content.parse::()?; 20 | let lookahead = content.lookahead1(); 21 | Ok(if lookahead.peek(keywords::aux_data) { 22 | let _ = content.parse::()?; 23 | Self::AuxData 24 | } else if lookahead.peek(keywords::aux_params) { 25 | let _ = content.parse::()?; 26 | Self::AuxParams 27 | } else { 28 | return Err(crate::Error::BadAux(endpoint.span()).into()); 29 | }) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /wtx/src/http/generic_response.rs: -------------------------------------------------------------------------------- 1 | use crate::http::Version; 2 | 3 | /// HTTP response 4 | pub trait GenericResponse { 5 | /// Code 6 | fn code(&self) -> u16; 7 | 8 | /// Version 9 | fn version(&self) -> Version; 10 | } 11 | 12 | impl GenericResponse for () { 13 | #[inline] 14 | fn code(&self) -> u16 { 15 | 0 16 | } 17 | 18 | #[inline] 19 | fn version(&self) -> Version { 20 | Version::default() 21 | } 22 | } 23 | 24 | #[cfg(feature = "httparse")] 25 | mod httparse { 26 | use crate::{ 27 | http::{GenericResponse, Version}, 28 | misc::_unlikely_unreachable, 29 | }; 30 | 31 | impl GenericResponse for httparse::Response<'_, '_> { 32 | #[inline] 33 | fn code(&self) -> u16 { 34 | if let Some(el) = self.code { el } else { _unlikely_unreachable() } 35 | } 36 | 37 | #[inline] 38 | fn version(&self) -> Version { 39 | match self.version { 40 | Some(0) => Version::Http1, 41 | Some(1) => Version::Http1_1, 42 | _ => _unlikely_unreachable(), 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /wtx/src/de.rs: -------------------------------------------------------------------------------- 1 | //! Decode/Encode 2 | //! 3 | //! Groups different dependencies that transform different types of data. 4 | 5 | #[macro_use] 6 | mod macros; 7 | 8 | mod csv; 9 | mod de_controller; 10 | mod dec_error; 11 | mod decode; 12 | mod encode; 13 | pub mod format; 14 | mod from_radix_10; 15 | mod hex; 16 | mod num_array; 17 | mod percent_encoding; 18 | pub mod protocol; 19 | 20 | pub use csv::Csv; 21 | pub use de_controller::DEController; 22 | pub use dec_error::DecError; 23 | pub use decode::{Decode, DecodeSeq}; 24 | pub use encode::Encode; 25 | pub use from_radix_10::{FromRadix10, FromRadix10Error}; 26 | pub use hex::{HexDisplay, HexEncMode, HexError, decode_hex, encode_hex}; 27 | pub use num_array::{ 28 | I8String, I16String, I32String, I64String, U8String, U16String, U32String, U64String, i8_string, 29 | i16_string, i32_string, i64_string, u8_string, u16_string, u32_string, u64_string, 30 | }; 31 | pub use percent_encoding::{AsciiSet, PercentDecode, PercentEncode}; 32 | 33 | /// Identifier used to track the number of issued requests. 34 | pub type Id = u64; 35 | -------------------------------------------------------------------------------- /wtx-instances/generic-examples/environment-variables.rs: -------------------------------------------------------------------------------- 1 | //! `EnvVars` allows the interactive reading of environment variables. 2 | 3 | extern crate wtx; 4 | extern crate wtx_macros; 5 | 6 | use std::sync::OnceLock; 7 | use wtx::{ 8 | calendar::{DateTime, Utc}, 9 | misc::EnvVars, 10 | }; 11 | 12 | static VARS: OnceLock = OnceLock::new(); 13 | 14 | fn main() -> wtx::Result<()> { 15 | let _rslt = VARS.set(EnvVars::from_available()?.finish()); 16 | let Vars { now, origin, port, rust_log } = VARS.wait(); 17 | println!("`NOW={now:?}`, `ORIGIN={origin}`, `PORT={port}` and `RUST_LOG={rust_log:?}`"); 18 | Ok(()) 19 | } 20 | 21 | #[derive(Debug, wtx_macros::FromVars)] 22 | struct Vars { 23 | #[from_vars(map_now)] 24 | now: Option>, 25 | origin: String, 26 | #[from_vars(map_port)] 27 | port: u16, 28 | rust_log: Option, 29 | } 30 | 31 | fn map_now(var: String) -> wtx::Result> { 32 | Ok(DateTime::from_iso8601(var.as_bytes())?) 33 | } 34 | 35 | fn map_port(var: String) -> wtx::Result { 36 | Ok(var.parse()?) 37 | } 38 | -------------------------------------------------------------------------------- /wtx/src/web_socket/op_code.rs: -------------------------------------------------------------------------------- 1 | create_enum! { 2 | /// Defines how to interpret the payload data. 3 | #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] 4 | #[derive(Clone, Copy, Debug, Eq, PartialEq)] 5 | pub enum OpCode { 6 | /// Continuation of a previous frame. 7 | Continuation = (0b0000_0000), 8 | /// UTF-8 text. 9 | Text = (0b0000_0001), 10 | /// Opaque bytes. 11 | Binary = (0b0000_0010), 12 | /// Connection is closed. 13 | Close = (0b0000_1000), 14 | /// Test reachability. 15 | Ping = (0b0000_1001), 16 | /// Response of a ping frame. 17 | Pong = (0b0000_1010), 18 | } 19 | } 20 | 21 | impl OpCode { 22 | /// If this instance is of type [`OpCode::Close`]. 23 | #[inline] 24 | pub const fn is_close(self) -> bool { 25 | matches!(self, OpCode::Close) 26 | } 27 | 28 | pub(crate) const fn is_control(self) -> bool { 29 | matches!(self, OpCode::Close | OpCode::Ping | OpCode::Pong) 30 | } 31 | 32 | pub(crate) const fn is_text(self) -> bool { 33 | matches!(self, OpCode::Text) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /wtx-instances/http-server-framework-examples/http-server-framework-redirect.rs: -------------------------------------------------------------------------------- 1 | //! Different types of redirects. 2 | 3 | use wtx::{ 4 | http::{ 5 | ReqResBuffer, StatusCode, 6 | server_framework::{Redirect, Router, ServerFrameworkBuilder, StateClean, get}, 7 | }, 8 | rng::{Xorshift64, simple_seed}, 9 | }; 10 | 11 | #[tokio::main] 12 | async fn main() -> wtx::Result<()> { 13 | let router = 14 | Router::paths(wtx::paths!(("/permanent", get(permanent)), ("/temporary", get(temporary))))?; 15 | ServerFrameworkBuilder::new(Xorshift64::from(simple_seed()), router) 16 | .without_aux() 17 | .tokio( 18 | &wtx_instances::host_from_args(), 19 | |error| eprintln!("{error}"), 20 | |_| Ok(()), 21 | |_| Ok(()), 22 | |error| eprintln!("{error}"), 23 | ) 24 | .await 25 | } 26 | 27 | async fn permanent() -> Redirect { 28 | Redirect::permanent("/some/path") 29 | } 30 | 31 | async fn temporary(state: StateClean<'_, (), (), ReqResBuffer>) -> wtx::Result { 32 | Redirect::temporary_raw(&mut state.req.rrd.headers, "/another/path") 33 | } 34 | -------------------------------------------------------------------------------- /wtx/src/database/schema_manager/migration/db_migration_group.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | database::schema_manager::{Uid, migration::migration_group_common::MigrationGroupCommon}, 3 | misc::Lease, 4 | }; 5 | 6 | /// A group of migrations retrieved from a database. 7 | #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] 8 | pub struct DbMigrationGroup { 9 | common: MigrationGroupCommon, 10 | version: u32, 11 | } 12 | 13 | impl DbMigrationGroup 14 | where 15 | S: Lease, 16 | { 17 | /// Creates a new instance from all necessary parameters. 18 | #[inline] 19 | pub const fn new(name: S, uid: Uid, version: u32) -> Self { 20 | Self { common: MigrationGroupCommon::new(name, uid), version } 21 | } 22 | 23 | /// Name 24 | #[inline] 25 | pub fn name(&self) -> &str { 26 | self.common.name.lease() 27 | } 28 | 29 | /// User ID 30 | #[inline] 31 | pub const fn uid(&self) -> Uid { 32 | self.common.uid 33 | } 34 | 35 | /// Used to track API changes. 36 | #[inline] 37 | pub const fn version(&self) -> u32 { 38 | self.version 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /wtx/src/database/client/mysql/command.rs: -------------------------------------------------------------------------------- 1 | create_enum! { 2 | #[derive(Clone, Copy, Debug, PartialEq)] 3 | pub(crate) enum Command { 4 | ComSleep = (0), 5 | ComQuit = (1), 6 | ComInitDb = (2), 7 | ComQuery = (3), 8 | ComFieldList = (4), 9 | ComCreateDb = (5), 10 | ComDropDb = (6), 11 | ComRefresh = (7), 12 | ComDeprecated1 = (8), 13 | ComStatistics = (9), 14 | ComProcessInfo = (10), 15 | ComConnect = (11), 16 | ComProcessKill = (12), 17 | ComDebug = (13), 18 | ComPing = (14), 19 | ComTime = (15), 20 | ComDelayedInsert = (16), 21 | ComChangeUser = (17), 22 | ComBinlogDump = (18), 23 | ComTableDump = (19), 24 | ComConnectOut = (20), 25 | ComRegisterSlave = (21), 26 | ComStmtPrepare = (22), 27 | ComStmtExecute = (23), 28 | ComStmtSendLongData = (24), 29 | ComStmtClose = (25), 30 | ComStmtReset = (26), 31 | ComSetOption = (27), 32 | ComStmtFetch = (28), 33 | ComDaemon = (29), 34 | ComBinlogDumpGtid = (30), 35 | ComResetConnection = (31), 36 | ComEnd = (32), 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /wtx/src/collection.rs: -------------------------------------------------------------------------------- 1 | //! Collection types 2 | 3 | #[macro_use] 4 | mod macros; 5 | 6 | mod array_string; 7 | mod array_vector; 8 | mod array_wrapper; 9 | mod auto_clear; 10 | mod blocks_deque; 11 | mod clear; 12 | mod deque; 13 | mod expansion_ty; 14 | mod linear_storage; 15 | mod misc; 16 | mod truncate; 17 | mod try_extend; 18 | mod vector; 19 | 20 | pub use array_string::{ 21 | ArrayString, ArrayStringError, ArrayStringU8, ArrayStringU16, ArrayStringU32, ArrayStringUsize, 22 | }; 23 | pub use array_vector::{ 24 | ArrayIntoIter, ArrayVector, ArrayVectorError, ArrayVectorU8, ArrayVectorU16, ArrayVectorU32, 25 | ArrayVectorUsize, 26 | }; 27 | pub use array_wrapper::ArrayWrapper; 28 | pub use auto_clear::AutoClear; 29 | pub use blocks_deque::{Block, BlocksDeque, BlocksDequeError}; 30 | pub use clear::Clear; 31 | pub use deque::{Deque, DequeueError}; 32 | pub use expansion_ty::ExpansionTy; 33 | pub use linear_storage::linear_storage_len::LinearStorageLen; 34 | pub use misc::backward_deque_idx; 35 | pub use truncate::Truncate; 36 | pub use try_extend::TryExtend; 37 | pub use vector::{Vector, VectorError}; 38 | -------------------------------------------------------------------------------- /wtx/src/database/schema_manager/integration_tests/backend.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | calendar::{Duration, Instant}, 3 | collection::Vector, 4 | database::{ 5 | Database, Identifier, 6 | schema_manager::{ 7 | Commands, DbMigration, SchemaManagement, 8 | integration_tests::{_migrate_doc_test, AuxTestParams}, 9 | }, 10 | }, 11 | }; 12 | use alloc::string::String; 13 | 14 | pub(crate) async fn _backend_has_migration_with_utc_time( 15 | (buffer_cmd, buffer_db_migrations, _): ( 16 | &mut String, 17 | &mut Vector, 18 | &mut Vector, 19 | ), 20 | c: &mut Commands, 21 | _: AuxTestParams, 22 | ) where 23 | DB: Database, 24 | E: SchemaManagement, 25 | { 26 | let mg = _migrate_doc_test(c).await; 27 | c.executor_mut().migrations(buffer_cmd, &mg, buffer_db_migrations).await.unwrap(); 28 | let created_on = *buffer_db_migrations[0].created_on(); 29 | let range = created_on..=created_on.add(Duration::from_seconds(5).unwrap()).unwrap(); 30 | assert!(range.contains(&Instant::now_date_time(0).unwrap())); 31 | } 32 | -------------------------------------------------------------------------------- /wtx/src/calendar/ce_days.rs: -------------------------------------------------------------------------------- 1 | use crate::calendar::{CalendarError, Date}; 2 | 3 | /// Number of days since the common era (0001-01-01) 4 | #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] 5 | pub struct CeDays(i32); 6 | 7 | impl CeDays { 8 | /// Instance with the maximum allowed value. 9 | pub const MAX: Self = Self(Date::MAX.ce_days()); 10 | /// Instance with the minimum allowed value. 11 | pub const MIN: Self = Self(Date::MIN.ce_days()); 12 | 13 | /// Creates a new instance from a valid `num` number. 14 | #[inline] 15 | pub const fn from_num(num: i32) -> Result { 16 | if num < Date::MIN.ce_days() || num > Date::MAX.ce_days() { 17 | return Err(CalendarError::InvalidCeDays { received: num }); 18 | } 19 | Ok(Self(num)) 20 | } 21 | 22 | /// Integer representation 23 | #[inline] 24 | pub const fn num(&self) -> i32 { 25 | self.0 26 | } 27 | } 28 | 29 | impl TryFrom for CeDays { 30 | type Error = crate::Error; 31 | 32 | #[inline] 33 | fn try_from(from: i32) -> Result { 34 | Ok(Self::from_num(from)?) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /wtx/src/client_api_framework/misc/request_limit.rs: -------------------------------------------------------------------------------- 1 | use core::time::Duration; 2 | 3 | /// Determines how many times a series of requests can be performed within a certain duration 4 | #[derive(Clone, Copy, Debug)] 5 | pub struct RequestLimit { 6 | duration: Duration, 7 | limit: u16, 8 | } 9 | 10 | impl RequestLimit { 11 | /// If `duration` is zero then this structure is basically a no-op. Limits of value `0` will be 12 | /// converted to `1` to avoid infinite hangs. 13 | #[inline] 14 | pub fn new(limit: u16, duration: Duration) -> Self { 15 | Self { duration, limit: limit.max(1) } 16 | } 17 | 18 | /// Useful for tests. 19 | #[inline] 20 | pub const fn unlimited() -> Self { 21 | Self { duration: Duration::from_secs(0), limit: u16::MAX } 22 | } 23 | 24 | /// The interval range that can contain a maximum number of [`Self::limit`] requests 25 | #[inline] 26 | pub const fn duration(&self) -> &Duration { 27 | &self.duration 28 | } 29 | 30 | /// Upper bound or maximum possible number of requests 31 | #[inline] 32 | pub const fn limit(&self) -> u16 { 33 | self.limit 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /wtx/src/database/client/mysql/ty_params.rs: -------------------------------------------------------------------------------- 1 | use crate::database::client::mysql::{Ty, flag::Flag, protocol::column_res::ColumnRes}; 2 | 3 | /// [`Ty`] with metadata. 4 | #[derive(Clone, Copy, Debug, PartialEq)] 5 | pub struct TyParams { 6 | flags: u16, 7 | ty: Ty, 8 | } 9 | 10 | impl TyParams { 11 | /// Constructor 12 | pub const fn new(flags: u16, ty: Ty) -> Self { 13 | Self { flags, ty } 14 | } 15 | 16 | pub(crate) const fn binary(ty: Ty) -> Self { 17 | Self { flags: Flag::Binary as u16, ty } 18 | } 19 | 20 | pub(crate) const fn empty(ty: Ty) -> Self { 21 | Self { flags: 0, ty } 22 | } 23 | 24 | pub(crate) const fn unsigned(ty: Ty) -> Self { 25 | Self { flags: Flag::Binary as u16 | Flag::Unsigned as u16, ty } 26 | } 27 | 28 | pub(crate) const fn from_column_res(column_res: &ColumnRes) -> Self { 29 | Self { flags: column_res.flags, ty: column_res.ty } 30 | } 31 | 32 | /// Bitflag combination that compose a metadata. 33 | pub const fn flags(&self) -> u16 { 34 | self.flags 35 | } 36 | 37 | /// See [`Ty`]. 38 | pub const fn ty(&self) -> Ty { 39 | self.ty 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /wtx/src/misc/connection_state.rs: -------------------------------------------------------------------------------- 1 | /// The state of a connection between two parties. 2 | #[derive(Clone, Copy, Debug)] 3 | pub enum ConnectionState { 4 | /// Is locally closed. Does not necessary means that both parties are in the same state. 5 | Closed, 6 | /// Is locally open. Does not necessary means that both parties are in the same state. 7 | Open, 8 | } 9 | 10 | impl ConnectionState { 11 | /// Shortcut for [`ConnectionState::Closed`]. 12 | #[inline] 13 | pub const fn is_closed(self) -> bool { 14 | matches!(self, Self::Closed) 15 | } 16 | 17 | /// Shortcut for [`ConnectionState::Open`]. 18 | #[inline] 19 | pub const fn is_open(self) -> bool { 20 | matches!(self, Self::Open) 21 | } 22 | } 23 | 24 | impl From for ConnectionState { 25 | #[inline] 26 | fn from(from: bool) -> Self { 27 | if from { Self::Open } else { Self::Closed } 28 | } 29 | } 30 | 31 | impl From for bool { 32 | #[inline] 33 | fn from(from: ConnectionState) -> Self { 34 | match from { 35 | ConnectionState::Closed => false, 36 | ConnectionState::Open => true, 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /wtx-macros/src/client_api_framework/pkg/fir/fir_custom_field_attr.rs: -------------------------------------------------------------------------------- 1 | use crate::client_api_framework::pkg::{ 2 | fir::fir_custom_field_field_attr::FirCustomFieldFieldAttr, keywords, 3 | }; 4 | use syn::{ 5 | parse::{Parse, ParseStream}, 6 | spanned::Spanned as _, 7 | }; 8 | 9 | #[derive(Debug)] 10 | pub(crate) enum FirCustomFieldAttr { 11 | Field(FirCustomFieldFieldAttr), 12 | } 13 | 14 | impl Parse for FirCustomFieldAttr { 15 | fn parse(input: ParseStream<'_>) -> syn::Result { 16 | let _ = input.parse::()?; 17 | let content; 18 | syn::bracketed!(content in input); 19 | let endpoint = content.parse::()?; 20 | let _ = content.parse::()?; 21 | let lookahead = content.lookahead1(); 22 | Ok(if lookahead.peek(keywords::field) { 23 | let _ = content.parse::()?; 24 | let content_paren; 25 | syn::parenthesized!(content_paren in content); 26 | Self::Field(content_paren.parse::()?) 27 | } else { 28 | return Err(crate::Error::BadField(endpoint.span()).into()); 29 | }) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /wtx/src/database/client/postgres/tys/uuid.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | database::{ 3 | Typed, 4 | client::postgres::{DecodeWrapper, EncodeWrapper, Postgres, Ty}, 5 | }, 6 | de::{Decode, Encode}, 7 | }; 8 | use uuid::Uuid; 9 | 10 | impl<'de, E> Decode<'de, Postgres> for Uuid 11 | where 12 | E: From, 13 | { 14 | #[inline] 15 | fn decode(dw: &mut DecodeWrapper<'de, '_>) -> Result { 16 | let elem = Uuid::from_slice(dw.bytes()).map_err(Into::into)?; 17 | Ok(elem) 18 | } 19 | } 20 | 21 | impl Encode> for Uuid 22 | where 23 | E: From, 24 | { 25 | #[inline] 26 | fn encode(&self, ew: &mut EncodeWrapper<'_, '_>) -> Result<(), E> { 27 | ew.buffer().extend_from_slice(self.as_bytes())?; 28 | Ok(()) 29 | } 30 | } 31 | 32 | impl Typed> for Uuid 33 | where 34 | E: From, 35 | { 36 | #[inline] 37 | fn runtime_ty(&self) -> Option { 38 | >>::static_ty() 39 | } 40 | 41 | #[inline] 42 | fn static_ty() -> Option { 43 | Some(Ty::Uuid) 44 | } 45 | } 46 | 47 | test!(uuid, Uuid, Uuid::max()); 48 | -------------------------------------------------------------------------------- /wtx/src/de/format/de.rs: -------------------------------------------------------------------------------- 1 | use crate::de::{ 2 | Decode, DecodeSeq, Encode, 3 | format::{DecodeWrapper, EncodeWrapper}, 4 | }; 5 | 6 | /// `D`ecode/`E`ncode 7 | #[derive(Debug)] 8 | pub struct De(core::marker::PhantomData); 9 | 10 | impl crate::de::DEController for De { 11 | type DecodeWrapper<'inner, 'outer, 'rem> 12 | = DecodeWrapper<'inner> 13 | where 14 | 'inner: 'outer; 15 | type Error = crate::Error; 16 | type EncodeWrapper<'inner, 'outer, 'rem> 17 | = EncodeWrapper<'inner> 18 | where 19 | 'inner: 'outer; 20 | } 21 | 22 | impl Decode<'_, De> for () { 23 | #[inline] 24 | fn decode(_: &mut DecodeWrapper<'_>) -> crate::Result { 25 | Ok(()) 26 | } 27 | } 28 | 29 | impl DecodeSeq<'_, De> for () { 30 | #[inline] 31 | fn decode_seq( 32 | _: &mut crate::collection::Vector, 33 | _: &mut DecodeWrapper<'_>, 34 | ) -> crate::Result<()> { 35 | Ok(()) 36 | } 37 | } 38 | 39 | impl Encode> for () { 40 | #[inline] 41 | fn encode(&self, _: &mut EncodeWrapper<'_>) -> Result<(), crate::Error> { 42 | Ok(()) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /wtx/src/web_socket/web_socket_error.rs: -------------------------------------------------------------------------------- 1 | /// WebSocket Error 2 | #[derive(Debug)] 3 | pub enum WebSocketError { 4 | /// HTTP headers must be unique. 5 | DuplicatedHeader, 6 | /// Received close frame has invalid parameters. 7 | InvalidCloseFrame, 8 | /// It was not possible to create a close frame with the given parameters. 9 | InvalidCloseFrameParams, 10 | /// Received an invalid header compression parameter. 11 | InvalidCompressionHeaderParameter, 12 | /// The client sent an invalid mask bit. 13 | InvalidMaskBit, 14 | /// Server received a frame without a mask. 15 | MissingFrameMask, 16 | /// Handshake response should return a 101 code. 17 | MissingSwitchingProtocols { 18 | /// The actual response code received 19 | found: Option, 20 | }, 21 | /// Received control frame wasn't supposed to be fragmented. 22 | UnexpectedFragmentedControlFrame, 23 | /// For example, the first frame of a message is a continuation. 24 | UnexpectedFrame, 25 | /// Control frames have a maximum allowed size. 26 | VeryLargeControlFrame, 27 | /// Frame payload exceeds the defined threshold. 28 | VeryLargePayload, 29 | } 30 | -------------------------------------------------------------------------------- /wtx/src/web_socket/compression/compression_level.rs: -------------------------------------------------------------------------------- 1 | create_enum! { 2 | /// A scale from 0 to 9 where 0 means "no compression" and 9 means "take as long as you'd like". 3 | #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] 4 | pub enum CompressionLevel { 5 | /// Zero 6 | Zero = (0), 7 | /// One 8 | One = (1), 9 | /// Two 10 | Two = (2), 11 | /// Three 12 | Three = (3), 13 | /// Four 14 | Four = (4), 15 | /// Five 16 | #[default] 17 | Five = (5), 18 | /// Six 19 | Six = (6), 20 | /// Seven 21 | Seven = (7), 22 | /// Eight 23 | Eight = (8), 24 | /// Nine 25 | Nine = (9), 26 | } 27 | } 28 | 29 | impl CompressionLevel { 30 | /// Instance that represents the minimum allowed value. 31 | pub const MIN: Self = Self::Zero; 32 | /// Instance that represents the maximum allowed value. 33 | pub const MAX: Self = Self::Nine; 34 | } 35 | 36 | #[cfg(feature = "flate2")] 37 | impl From for flate2::Compression { 38 | #[inline] 39 | fn from(from: CompressionLevel) -> Self { 40 | flate2::Compression::new(u8::from(from).into()) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /wtx/src/database/client/mysql/protocol/prepare_res.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | database::client::mysql::{ 3 | MysqlError, 4 | protocol::{Protocol, decode_wrapper_protocol::DecodeWrapperProtocol}, 5 | }, 6 | de::Decode, 7 | }; 8 | 9 | #[derive(Debug)] 10 | pub(crate) struct PrepareRes { 11 | pub(crate) columns: u16, 12 | pub(crate) params: u16, 13 | pub(crate) statement_id: u32, 14 | } 15 | 16 | impl<'de, DO, E> Decode<'de, Protocol> for PrepareRes 17 | where 18 | E: From, 19 | { 20 | #[inline] 21 | fn decode(dw: &mut DecodeWrapperProtocol<'de, '_, DO>) -> Result { 22 | let [a, b, c, d, e, f, g, h, i, _, k, l, ..] = dw.bytes else { 23 | return Err(E::from(MysqlError::InvalidPrepareBytes.into())); 24 | }; 25 | if *a != 0 { 26 | return Err(E::from(MysqlError::InvalidPrepareBytes.into())); 27 | } 28 | let statement_id = u32::from_le_bytes([*b, *c, *d, *e]); 29 | let columns = u16::from_le_bytes([*f, *g]); 30 | let params = u16::from_le_bytes([*h, *i]); 31 | let _warnings = u16::from_le_bytes([*k, *l]); 32 | Ok(Self { columns, params, statement_id }) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /wtx/src/database/client/rdbms/common_record.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | database::{ValueIdent, client::rdbms::statement::Statement}, 3 | misc::Lease, 4 | }; 5 | use core::{marker::PhantomData, ops::Range}; 6 | 7 | /// Record used by several database implementations 8 | #[derive(Debug)] 9 | pub(crate) struct CommonRecord<'exec, A, C, D, T> { 10 | pub(crate) phantom: PhantomData, 11 | pub(crate) record: &'exec [u8], 12 | pub(crate) stmt: Statement<'exec, A, C, T>, 13 | pub(crate) values_params: &'exec [(bool, Range)], 14 | } 15 | 16 | impl<'exec, A, C, D, T> CommonRecord<'exec, A, C, D, T> { 17 | pub(crate) const fn new( 18 | record: &'exec [u8], 19 | stmt: Statement<'exec, A, C, T>, 20 | values_params: &'exec [(bool, Range)], 21 | ) -> Self { 22 | Self { phantom: PhantomData, record, stmt, values_params } 23 | } 24 | } 25 | 26 | impl<'exec, A, C, D, T> ValueIdent> for &str 27 | where 28 | C: Lease, 29 | { 30 | fn idx(&self, input: &CommonRecord<'exec, A, C, D, T>) -> Option { 31 | input.stmt.columns().iter().position(|(column, _)| column.lease() == *self) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /wtx-macros/src/client_api_framework/item_with_attr_span.rs: -------------------------------------------------------------------------------- 1 | use core::mem; 2 | use proc_macro2::{Span, TokenStream}; 3 | use syn::Item; 4 | 5 | #[derive(Debug)] 6 | pub(crate) struct ItemWithAttrSpan { 7 | pub(crate) _content: C, 8 | pub(crate) item: I, 9 | pub(crate) span: Span, 10 | } 11 | 12 | impl<'module, C> From<(C, &'module Item, Span)> for ItemWithAttrSpan { 13 | #[inline] 14 | fn from((content, item, span): (C, &'module Item, Span)) -> Self { 15 | Self { _content: content, item, span } 16 | } 17 | } 18 | 19 | impl<'module, C> From<(C, &'module mut Item, Span)> for ItemWithAttrSpan { 20 | #[inline] 21 | fn from((content, item, span): (C, &'module mut Item, Span)) -> Self { 22 | Self { _content: content, item, span } 23 | } 24 | } 25 | 26 | impl<'module, C> From<(C, &'module mut Item, Span)> for ItemWithAttrSpan { 27 | #[inline] 28 | fn from((content, item, span): (C, &'module mut Item, Span)) -> Self { 29 | let mut actual_item = Item::Verbatim(TokenStream::new()); 30 | mem::swap(item, &mut actual_item); 31 | Self { _content: content, item: actual_item, span } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /wtx/src/calendar/day_of_year.rs: -------------------------------------------------------------------------------- 1 | use crate::calendar::CalendarError; 2 | 3 | /// This particular structure can represent at most one second in nanosecond. 4 | #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] 5 | pub struct DayOfYear(u16); 6 | 7 | impl DayOfYear { 8 | /// Instance with the minimum allowed value of `1` 9 | pub const ONE: Self = Self(1); 10 | /// Instance with the `365` value. 11 | pub const N365: Self = Self(365); 12 | /// Instance with the maximum allowed value of `366` 13 | pub const N366: Self = Self(366); 14 | 15 | /// Creates a new instance from a valid `num` number. 16 | #[inline] 17 | pub const fn from_num(num: u16) -> Result { 18 | if num < 1 || num > 366 { 19 | return Err(CalendarError::InvalidDayOfTheYear { received: num }); 20 | } 21 | Ok(Self(num)) 22 | } 23 | 24 | /// Integer representation 25 | #[inline] 26 | pub const fn num(&self) -> u16 { 27 | self.0 28 | } 29 | } 30 | 31 | impl TryFrom for DayOfYear { 32 | type Error = crate::Error; 33 | 34 | #[inline] 35 | fn try_from(from: u16) -> Result { 36 | Ok(Self::from_num(from)?) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /wtx/src/http/server_framework/res_finalizer.rs: -------------------------------------------------------------------------------- 1 | use crate::http::{ReqResBuffer, Request, StatusCode}; 2 | 3 | /// Modifies responses 4 | pub trait ResFinalizer { 5 | /// Finalize response 6 | fn finalize_response(self, req: &mut Request) -> Result; 7 | } 8 | 9 | impl ResFinalizer for () 10 | where 11 | E: From, 12 | { 13 | #[inline] 14 | fn finalize_response(self, req: &mut Request) -> Result { 15 | req.clear(); 16 | Ok(StatusCode::Ok) 17 | } 18 | } 19 | 20 | impl ResFinalizer for &'static str 21 | where 22 | E: From, 23 | { 24 | #[inline] 25 | fn finalize_response(self, req: &mut Request) -> Result { 26 | req.clear(); 27 | req.rrd.body.extend_from_copyable_slice(self.as_bytes())?; 28 | Ok(StatusCode::Ok) 29 | } 30 | } 31 | 32 | impl ResFinalizer for Result 33 | where 34 | E: From, 35 | T: ResFinalizer, 36 | { 37 | #[inline] 38 | fn finalize_response(self, req: &mut Request) -> Result { 39 | self.and_then(|elem| elem.finalize_response(req)) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /wtx/src/http/generic_header.rs: -------------------------------------------------------------------------------- 1 | /// HTTP header. 2 | pub trait GenericHeader { 3 | /// Name. 4 | fn name(&self) -> &[u8]; 5 | 6 | /// Value. 7 | fn value(&self) -> &[u8]; 8 | } 9 | 10 | impl GenericHeader for () { 11 | #[inline] 12 | fn name(&self) -> &[u8] { 13 | &[] 14 | } 15 | 16 | #[inline] 17 | fn value(&self) -> &[u8] { 18 | &[] 19 | } 20 | } 21 | 22 | impl GenericHeader for &T 23 | where 24 | T: GenericHeader, 25 | { 26 | #[inline] 27 | fn name(&self) -> &[u8] { 28 | (*self).name() 29 | } 30 | 31 | #[inline] 32 | fn value(&self) -> &[u8] { 33 | (*self).value() 34 | } 35 | } 36 | 37 | impl GenericHeader for [&[u8]; 2] { 38 | #[inline] 39 | fn name(&self) -> &[u8] { 40 | self[0] 41 | } 42 | 43 | #[inline] 44 | fn value(&self) -> &[u8] { 45 | self[1] 46 | } 47 | } 48 | 49 | #[cfg(feature = "httparse")] 50 | mod httparse { 51 | use crate::http::GenericHeader; 52 | 53 | impl GenericHeader for httparse::Header<'_> { 54 | #[inline] 55 | fn name(&self) -> &[u8] { 56 | self.name.as_bytes() 57 | } 58 | 59 | #[inline] 60 | fn value(&self) -> &[u8] { 61 | self.value 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /wtx/src/http/response.rs: -------------------------------------------------------------------------------- 1 | use crate::http::{Headers, ReqResData, StatusCode, Version}; 2 | 3 | /// Represents the response from an HTTP request. 4 | #[derive(Debug)] 5 | pub struct Response { 6 | /// See [`ReqResData`]. 7 | pub rrd: RRD, 8 | /// See [`StatusCode`]. 9 | pub status_code: StatusCode, 10 | /// See [`Version`]. 11 | pub version: Version, 12 | } 13 | 14 | impl Response { 15 | /// Constructor shortcut 16 | #[inline] 17 | pub const fn new(rrd: RRD, status_code: StatusCode, version: Version) -> Self { 18 | Self { rrd, status_code, version } 19 | } 20 | 21 | /// Constructor that defaults to an HTTP/2 version. 22 | #[inline] 23 | pub const fn http2(data: RRD, status_code: StatusCode) -> Self { 24 | Self { rrd: data, status_code, version: Version::Http2 } 25 | } 26 | } 27 | 28 | impl Response 29 | where 30 | RRD: ReqResData, 31 | { 32 | /// Shortcut to access the body of `data`. 33 | #[inline] 34 | pub fn body(&self) -> &RRD::Body { 35 | self.rrd.body() 36 | } 37 | 38 | /// Shortcut to access the headers of `data`. 39 | #[inline] 40 | pub fn headers(&self) -> &Headers { 41 | self.rrd.headers() 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /wtx-instances/src/bin/autobahn-client.rs: -------------------------------------------------------------------------------- 1 | //! WebSocket autobahn client. 2 | 3 | use wtx::{ 4 | collection::Vector, 5 | web_socket::{Frame, OpCode, WebSocketPayloadOrigin}, 6 | }; 7 | use wtx_instances::{autobahn_case_conn, autobahn_close, autobahn_get_case_count}; 8 | 9 | #[tokio::main] 10 | async fn main() -> wtx::Result<()> { 11 | let host = "127.0.0.1:9080"; 12 | let mut buffer = Vector::new(); 13 | for case in 1..=autobahn_get_case_count(&mut buffer, host).await? { 14 | let mut ws = autobahn_case_conn(case, host).await?; 15 | let (mut common, mut reader, mut writer) = ws.parts_mut(); 16 | loop { 17 | let mut frame = 18 | match reader.read_frame(&mut buffer, &mut common, WebSocketPayloadOrigin::Adaptive).await { 19 | Err(_err) => { 20 | ws.write_frame(&mut Frame::new_fin(OpCode::Close, &mut [])).await?; 21 | break; 22 | } 23 | Ok(elem) => elem, 24 | }; 25 | match frame.op_code() { 26 | OpCode::Binary | OpCode::Text => writer.write_frame(&mut common, &mut frame).await?, 27 | OpCode::Close => break, 28 | _ => {} 29 | } 30 | } 31 | } 32 | autobahn_close(host).await 33 | } 34 | -------------------------------------------------------------------------------- /wtx/src/stream/stream_writer.rs: -------------------------------------------------------------------------------- 1 | /// A stream of values written asynchronously. 2 | pub trait StreamWriter { 3 | /// Attempts to write ***all*** `bytes`. 4 | fn write_all(&mut self, bytes: &[u8]) -> impl Future>; 5 | 6 | /// Attempts to write ***all*** `bytes` of all slices in a single syscall. 7 | /// 8 | /// # Panics 9 | /// 10 | /// If the length of the outermost slice is greater than 8. 11 | fn write_all_vectored(&mut self, bytes: &[&[u8]]) -> impl Future>; 12 | } 13 | 14 | impl StreamWriter for &mut T 15 | where 16 | T: StreamWriter, 17 | { 18 | #[inline] 19 | async fn write_all(&mut self, bytes: &[u8]) -> crate::Result<()> { 20 | (**self).write_all(bytes).await 21 | } 22 | 23 | #[inline] 24 | async fn write_all_vectored(&mut self, bytes: &[&[u8]]) -> crate::Result<()> { 25 | (**self).write_all_vectored(bytes).await 26 | } 27 | } 28 | 29 | impl StreamWriter for () { 30 | #[inline] 31 | async fn write_all(&mut self, _: &[u8]) -> crate::Result<()> { 32 | Ok(()) 33 | } 34 | 35 | #[inline] 36 | async fn write_all_vectored(&mut self, _: &[&[u8]]) -> crate::Result<()> { 37 | Ok(()) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /.certs/root-ca.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDGzCCAgOgAwIBAgIULfMxOCpH518ImycugYA+u89m790wDQYJKoZIhvcNAQEL 3 | BQAwHTELMAkGA1UEBhMCRkkxDjAMBgNVBAMMBXZhaGlkMB4XDTI1MDIyODEzMTE1 4 | MFoXDTMwMDIyNzEzMTE1MFowHTELMAkGA1UEBhMCRkkxDjAMBgNVBAMMBXZhaGlk 5 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApHGj8QHvYFWmjaIbrn7m 6 | I0OW3PVD0ICsQiTHN2F28MvBCbDG1jpiVMl4guaZYQP1EOkfPs9qqmhPlF2xo6ub 7 | 4zn/7SzqnAYect8lZU0528AfmsIKyGXN334jN4e8i6n8kTPGBUnoAsRAvMfHiUHl 8 | LONFmZGvU4yl/NqyKlzUUrWmIPABz8zhsVA6JRJOsXqq5H/FUZYXtjIx7boZbbk4 9 | UYpEt5dnrEIabzTa2o01WwYzVfYLMyOjpqsrAX02AdetCLDjSAabgNISY3pDgcDz 10 | eYeKFMqu0LsEgEUmUN+Jz4E9wixS2Wc7iSVn3NGYqnSIDJwuREkFhyAPAAt3zPZp 11 | pwIDAQABo1MwUTAdBgNVHQ4EFgQUBy1s3M39Wf4s158jKT+KbPZyDhgwHwYDVR0j 12 | BBgwFoAUBy1s3M39Wf4s158jKT+KbPZyDhgwDwYDVR0TAQH/BAUwAwEB/zANBgkq 13 | hkiG9w0BAQsFAAOCAQEAP1beR2/2+A/Ns3JACZNWWnVSh/hOpnVyh84h074K0PgQ 14 | SWxOpIo4h7nJZYbYsX0cOJjFeL26wL/vFwvj51Giv2nv+KRYDUptmRZk12s04H4P 15 | ea2OyJd0uNVIiE1HMhaFKFP7oDJHtxFGOhDmpaK+OtNgiVpCPRj/X5ykWevpIJyu 16 | 1yihcC/pb8AnbNutoGGHPRafmRqYKv8o0O6Zo8a4jBbAPczx0isrOA4Rimc4pzj8 17 | rR9/Vp39U96cqMN5VJjq76e+mMvAIFok96e1kxUiAR3MxAHBEJHy67mgXUnpFmo8 18 | OJr01JQiBJh4DTPuk6ixLGX3PpbVkHh4aV0bXxBRkQ== 19 | -----END CERTIFICATE----- 20 | -------------------------------------------------------------------------------- /wtx/src/calendar/format/push.rs: -------------------------------------------------------------------------------- 1 | use crate::{calendar::Date, collection::ArrayStringU8, de::i16_string}; 2 | 3 | #[inline] 4 | pub(crate) fn push_four_digit_year( 5 | date: Date, 6 | string: &mut ArrayStringU8, 7 | ) -> crate::Result<()> { 8 | let year = i16_string(date.year().num()); 9 | let (num, zeros) = if year.len() <= 4 { 10 | if let [b'-', rest @ ..] = year.as_bytes() { 11 | string.push('-')?; 12 | (rest, 5u8.wrapping_sub(year.len())) 13 | } else { 14 | (year.as_bytes(), 4u8.wrapping_sub(year.len())) 15 | } 16 | } else { 17 | (year.as_bytes(), 0) 18 | }; 19 | for _ in 0..zeros { 20 | string.push('0')?; 21 | } 22 | for elem in num { 23 | string.push((*elem).into())?; 24 | } 25 | Ok(()) 26 | } 27 | 28 | #[inline] 29 | pub(crate) fn push_two_space_day( 30 | date: Date, 31 | string: &mut ArrayStringU8, 32 | ) -> crate::Result<()> { 33 | let [a, b] = date.day().num_str().as_bytes() else { 34 | return Ok(()); 35 | }; 36 | if *a == b'0' { 37 | string.push_str(date.day().num_str())?; 38 | } else { 39 | string.push((*a).into())?; 40 | string.push((*b).into())?; 41 | } 42 | Ok(()) 43 | } 44 | -------------------------------------------------------------------------------- /wtx/src/database/schema_manager/schema_manager_error.rs: -------------------------------------------------------------------------------- 1 | use crate::database::schema_manager::Uid; 2 | 3 | /// Schema Manager Error 4 | #[derive(Debug)] 5 | pub enum SchemaManagerError { 6 | /// The `seeds` parameter must be provided through the CLI or the configuration file. 7 | ChecksumMustBeANumber, 8 | /// Databases must be sorted and unique 9 | DatabasesMustBeSortedAndUnique, 10 | /// Different rollback user IDs 11 | DifferentRollbackUids, 12 | /// The group version of the migration group is older than the current supported version. 13 | DivergentGroupVersions(u32, u32), 14 | /// Divergent migrations 15 | DivergentMigration(Uid), 16 | /// Validation - Migrations number 17 | DivergentMigrationsNum { 18 | /// Expected 19 | expected: u32, 20 | /// Received 21 | received: u32, 22 | }, 23 | /// Migration file has invalid syntax, 24 | InvalidMigration, 25 | /// TOML parser only supports a subset of the official TOML specification 26 | TomlParserOnlySupportsStringsAndArraysOfStrings, 27 | /// TOML parser only supports a subset of the official TOML specification 28 | TomlValueIsTooLarge, 29 | /// Migration file has an empty attribute 30 | IncompleteSqlFile, 31 | } 32 | -------------------------------------------------------------------------------- /.scripts/internal-tests0.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | . "$(dirname "$0")/common.sh" --source-only 4 | 5 | $rt rustfmt 6 | $rt clippy -Aclippy::as_conversions,-Aclippy::modulo_arithmetic,-Aclippy::arbitrary_source_item_ordering,-Aclippy::doc-include-without-cfg,-Aclippy::little-endian-bytes,-Aclippy::panic-in-result-fn,-Aclippy::return_and_then,-Aclippy::used_underscore_items 7 | 8 | MIRIFLAGS="-Zmiri-disable-isolation" cargo miri test --features http2,postgres,web-socket -p wtx 9 | 10 | # WTX 11 | 12 | $rt check-generic wtx 13 | 14 | $rt test-with-features wtx _async-tests 15 | $rt test-with-features wtx _bench 16 | $rt test-with-features wtx _integration-tests 17 | $rt test-with-features wtx _tracing-tree 18 | $rt test-with-features wtx 32-tuple-impls 19 | $rt test-with-features wtx aes-gcm 20 | $rt test-with-features wtx arbitrary 21 | $rt test-with-features wtx argon2 22 | $rt test-with-features wtx async-net 23 | $rt test-with-features wtx base64 24 | $rt test-with-features wtx borsh 25 | $rt test-with-features wtx chacha20 26 | $rt test-with-features wtx client-api-framework 27 | $rt test-with-features wtx crossbeam-channel 28 | $rt test-with-features wtx crypto-common 29 | $rt test-with-features wtx database 30 | -------------------------------------------------------------------------------- /wtx/src/database/client/mysql/protocol/ok_res.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | database::client::mysql::{ 3 | MysqlError, 4 | protocol::{Protocol, decode_wrapper_protocol::DecodeWrapperProtocol, lenenc::Lenenc}, 5 | }, 6 | de::Decode, 7 | }; 8 | 9 | #[derive(Debug)] 10 | pub(crate) struct OkRes { 11 | pub(crate) statuses: u16, 12 | } 13 | 14 | impl Decode<'_, Protocol> for OkRes 15 | where 16 | E: From, 17 | { 18 | #[inline] 19 | fn decode(dw: &mut DecodeWrapperProtocol<'_, '_, DO>) -> Result { 20 | let [first, rest0 @ ..] = dw.bytes else { 21 | return Err(E::from(MysqlError::InvalidOkBytes.into())); 22 | }; 23 | if *first != 0 && *first != 254 { 24 | return Err(E::from(MysqlError::InvalidOkBytes.into())); 25 | } 26 | *dw.bytes = rest0; 27 | let _affected_rows = Lenenc::decode(dw)?.0; 28 | let _last_insert_id = Lenenc::decode(dw)?.0; 29 | let [a, b, c, d, rest1 @ ..] = dw.bytes else { 30 | return Err(E::from(MysqlError::InvalidOkBytes.into())); 31 | }; 32 | let statuses = u16::from_le_bytes([*a, *b]); 33 | let _warnings = u16::from_le_bytes([*c, *d]); 34 | *dw.bytes = rest1; 35 | Ok(Self { statuses }) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /wtx/src/de/protocol/misc.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "serde_json")] 2 | pub(crate) use serde_json::collect_using_serde_json; 3 | 4 | #[cfg(feature = "serde_json")] 5 | mod serde_json { 6 | use crate::{collection::Vector, misc::deserialize_seq_into_buffer_with_serde}; 7 | use serde::Deserialize; 8 | 9 | pub(crate) fn collect_using_serde_json<'de, T>( 10 | buffer: &mut Vector, 11 | bytes: &mut &'de [u8], 12 | ) -> crate::Result<()> 13 | where 14 | T: Deserialize<'de>, 15 | { 16 | deserialize_seq_into_buffer_with_serde(&mut serde_json::Deserializer::from_slice(bytes), buffer) 17 | } 18 | 19 | #[cfg(test)] 20 | mod tests { 21 | use crate::{collection::Vector, de::protocol::misc::serde_json::collect_using_serde_json}; 22 | 23 | #[derive(Debug, PartialEq, serde::Deserialize)] 24 | struct Foo { 25 | a: u8, 26 | b: u64, 27 | } 28 | 29 | #[test] 30 | fn array_is_deserialized() { 31 | let json = r#"[{"a":1,"b":90},{"a":7,"b":567}]"#; 32 | let mut vector = Vector::::new(); 33 | collect_using_serde_json(&mut vector, &mut json.as_bytes()).unwrap(); 34 | assert_eq!(vector.as_slice(), &[Foo { a: 1, b: 90 }, Foo { a: 7, b: 567 }]); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /wtx-docs/src/grpc/README.md: -------------------------------------------------------------------------------- 1 | # gRPC 2 | 3 | Basic implementation that currently only supports unary calls. gRPC is an high-performance remote procedure call framework developed by Google that enables efficient communication between distributed systems, particularly in microservices architectures. 4 | 5 | `wtx` does not provide built-in deserialization or serialization utilities capable of manipulate protobuf files. Instead, users are free to choose any third-party that generates Rust bindings and implements the internal `Deserialize` and `Serialize` traits. 6 | 7 | Due to the lack of an official parser, the definitions of a `Service` must be manually typed. 8 | 9 | Independent benchmarks are available at . 10 | 11 | ## Client Example 12 | 13 | To use this functionality, it is necessary to activate the `grpc-client` feature. 14 | 15 | ```rust,edition2024,no_run 16 | {{#rustdoc_include ../../../wtx-instances/generic-examples/grpc-client.rs}} 17 | ``` 18 | 19 | ## Server Example 20 | 21 | To use this functionality, it is necessary to activate the `grpc-server` feature. 22 | 23 | ```rust,edition2024,no_run 24 | {{#rustdoc_include ../../../wtx-instances/generic-examples/grpc-server.rs}} 25 | ``` 26 | -------------------------------------------------------------------------------- /wtx/src/database/client/mysql/protocol/initial_req.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | database::client::mysql::{ 3 | capability::Capability, 4 | collation::Collation, 5 | protocol::{Protocol, encode_wrapper_protocol::EncodeWrapperProtocol}, 6 | }, 7 | de::Encode, 8 | }; 9 | 10 | #[derive(Debug)] 11 | pub(crate) struct InitialReq { 12 | pub(crate) collation: Collation, 13 | pub(crate) max_packet_size: u32, 14 | } 15 | 16 | impl Encode> for InitialReq 17 | where 18 | E: From, 19 | { 20 | #[inline] 21 | fn encode(&self, ew: &mut EncodeWrapperProtocol<'_>) -> Result<(), E> { 22 | let capability_lhs = (*ew.capabilities >> 32) as u32; 23 | let capability_rhs = *ew.capabilities as u32; 24 | let _ = ew.encode_buffer.extend_from_copyable_slices([ 25 | capability_rhs.to_le_bytes().as_slice(), 26 | self.max_packet_size.to_le_bytes().as_slice(), 27 | &[self.collation.into()], 28 | &[0; 19], 29 | ])?; 30 | let mysql_n = u64::from(Capability::Mysql); 31 | ew.encode_buffer.extend_from_copyable_slice(&if *ew.capabilities & mysql_n == mysql_n { 32 | [0; 4] 33 | } else { 34 | capability_lhs.to_le_bytes() 35 | })?; 36 | Ok(()) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /wtx/src/database/client/mysql/protocol/packet_req.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | database::client::mysql::{ 3 | misc::packet_header, 4 | mysql_executor::MAX_PAYLOAD, 5 | protocol::{Protocol, encode_wrapper_protocol::EncodeWrapperProtocol}, 6 | }, 7 | de::Encode, 8 | misc::Usize, 9 | stream::Stream, 10 | }; 11 | use core::marker::PhantomData; 12 | 13 | pub(crate) struct PacketReq(pub(crate) T, pub(crate) PhantomData); 14 | 15 | impl PacketReq 16 | where 17 | E: From, 18 | T: Encode>, 19 | { 20 | pub(crate) async fn send( 21 | &self, 22 | ew: &mut EncodeWrapperProtocol<'_>, 23 | sequence_id: &mut u8, 24 | stream: &mut S, 25 | ) -> Result<(), E> 26 | where 27 | S: Stream, 28 | { 29 | let mut chunks = ew.encode_buffer.chunks_exact(*Usize::from(MAX_PAYLOAD)); 30 | for chunk in chunks.by_ref() { 31 | let header = packet_header(chunk.len(), sequence_id); 32 | stream.write_all_vectored(&[header.as_slice(), chunk]).await?; 33 | } 34 | let chunk = chunks.remainder(); 35 | let header = packet_header(chunk.len(), sequence_id); 36 | stream.write_all_vectored(&[header.as_slice(), chunk]).await?; 37 | Ok(()) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /.certs/cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDMTCCAhmgAwIBAgIUPJqPiqkz9u8yhgNp33wtkkagFb0wDQYJKoZIhvcNAQEL 3 | BQAwHTELMAkGA1UEBhMCRkkxDjAMBgNVBAMMBXZhaGlkMB4XDTI1MDIyODEzMTE1 4 | MFoXDTMwMDIyNzEzMTE1MFowHTELMAkGA1UEBhMCRkkxDjAMBgNVBAMMBXZhaGlk 5 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsnDBjqUrpFVUPekeNFiS 6 | X8NhwALcC2XBvPY5YjzGjh67t3Jf3rkuijWxbPO8CYx/s3CVBSUSsxXqzXQsyF0q 7 | Wf+rgjXjdY4k4dW2ItlKxpl82DxojVpkb+9lR4UJLKVjTTXUIV9cJ0n/BPrqUrRP 8 | n92R8StTos6UNVsQSRePMPq2Xf5zY/dCQm2mgpQTjaCP/mcYAi8OqyVszSexZlzk 9 | 4RHUpscKCRf9XwWmycvR4C8D4IZVI0wC7/3asR23JiJSUHCRxIW1m1X3MqKc3gdH 10 | 0We08lth/e/tn+R/v0Xg+9Dmvs5ZAAVpuj9OBKwKaiTyO/x2kUy1xVnssBXF8r7E 11 | mQIDAQABo2kwZzAfBgNVHSMEGDAWgBQHLWzczf1Z/izXnyMpP4ps9nIOGDAJBgNV 12 | HRMEAjAAMBoGA1UdEQQTMBGCCWxvY2FsaG9zdIcEfwAAATAdBgNVHQ4EFgQUR1AZ 13 | VIByZgflEamTYP10/hikPJcwDQYJKoZIhvcNAQELBQADggEBAHxXsOYUnVoaOnE4 14 | 0zGRz+Yw58wFcPMuYIFnk1Dz3cdhzzi8ruNCOGmR06F6H99gayIQ0CojaUUz7LSY 15 | SiZdKZKwoGntWj6JJoJCT9XkOJvoooly+R+ivDX2HLCQcZkkBBUjCl0jMFMYQ5Fx 16 | oQiXcpE7fu3l052jE9svXykLo4Pd8KFsBiIANrHZ7fcy9lPtkbdl59cwMCjw+Oex 17 | 98HkFBiuNRQF1fEfoYMRlxRiejIqm+SZ/rJzcnT09YzBQHbpo4MKOO7doq0/ewjP 18 | ZBdzadAZGs07HQOMuGuap2FiNOgcx5I+jdYIhZNvvxu+11iDjFEBSMcHiVriWvNz 19 | L5Ilu0g= 20 | -----END CERTIFICATE----- 21 | -------------------------------------------------------------------------------- /wtx/src/database/client/mysql/mysql_column_info.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | database::{ 3 | Identifier, 4 | client::{ 5 | mysql::{protocol::column_res::ColumnRes, ty_params::TyParams}, 6 | rdbms::column_info::ColumnInfo, 7 | }, 8 | }, 9 | misc::Lease, 10 | }; 11 | 12 | #[derive(Clone, Debug)] 13 | pub(crate) struct MysqlColumnInfo { 14 | pub(crate) name: Identifier, 15 | pub(crate) ty_params: TyParams, 16 | } 17 | 18 | impl MysqlColumnInfo { 19 | pub(crate) fn from_column_res(column_res: &ColumnRes) -> Self { 20 | let name = if column_res.alias.is_empty() { column_res.name } else { column_res.alias }; 21 | Self { name, ty_params: TyParams::from_column_res(column_res) } 22 | } 23 | } 24 | 25 | impl ColumnInfo for MysqlColumnInfo { 26 | type Ty = TyParams; 27 | 28 | #[inline] 29 | fn name(&self) -> &str { 30 | &self.name 31 | } 32 | 33 | #[inline] 34 | fn ty(&self) -> &Self::Ty { 35 | &self.ty_params 36 | } 37 | } 38 | 39 | impl Lease for MysqlColumnInfo { 40 | #[inline] 41 | fn lease(&self) -> &str { 42 | &self.name 43 | } 44 | } 45 | 46 | impl Lease for MysqlColumnInfo { 47 | #[inline] 48 | fn lease(&self) -> &TyParams { 49 | &self.ty_params 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /wtx/src/http2/stream_state.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, Copy, Eq, PartialEq)] 2 | pub(crate) enum StreamState { 3 | /// Final stage. Sent/received `END_STREAM`/`RST_STREAM` after 4 | /// [`StreamState::HalfClosedLocal`]/[`StreamState::HalfClosedRemote`] or sent/received 5 | /// `RST_STREAM` after [`StreamState::Open`]. 6 | Closed, 7 | /// The system sent `END_STREAM` after [`StreamState::Open`]. 8 | HalfClosedLocal, 9 | /// The system received `END_STREAM` after [`StreamState::Open`]. 10 | HalfClosedRemote, 11 | /// Initial state. Awaiting initial headers. 12 | Idle, 13 | /// The system is receiving data after [`StreamState::Idle`]. 14 | Open, 15 | } 16 | 17 | impl StreamState { 18 | /// If the system can send to a peer regardless of the frame type. 19 | pub(crate) const fn can_send(self) -> bool { 20 | if IS_CLIENT { 21 | matches!(self, Self::Idle | Self::Open) 22 | } else { 23 | matches!(self, Self::HalfClosedRemote | Self::Open) 24 | } 25 | } 26 | 27 | /// Received End Of Stream 28 | /// 29 | /// If the receiving part received an EOS from a peer. 30 | pub(crate) const fn recv_eos(self) -> bool { 31 | matches!(self, Self::HalfClosedRemote | Self::Closed) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /wtx/src/calendar/misc.rs: -------------------------------------------------------------------------------- 1 | // FIXME(STABLE): Constant traits 2 | 3 | pub(crate) const fn boolu16(val: bool) -> u16 { 4 | val as u16 5 | } 6 | 7 | pub(crate) const fn boolu32(val: bool) -> u32 { 8 | val as u32 9 | } 10 | 11 | pub(crate) const fn boolusize(val: bool) -> usize { 12 | val as usize 13 | } 14 | 15 | pub(crate) const fn i16i32(val: i16) -> i32 { 16 | val as i32 17 | } 18 | 19 | pub(crate) const fn i32i64(val: i32) -> i64 { 20 | val as i64 21 | } 22 | 23 | pub(crate) const fn u8i16(val: u8) -> i16 { 24 | val as i16 25 | } 26 | 27 | pub(crate) const fn u8i32(val: u8) -> i32 { 28 | val as i32 29 | } 30 | 31 | pub(crate) const fn u8i64(val: u8) -> i64 { 32 | val as i64 33 | } 34 | 35 | pub(crate) const fn u8u16(val: u8) -> u16 { 36 | val as u16 37 | } 38 | 39 | pub(crate) const fn u8u32(val: u8) -> u32 { 40 | val as u32 41 | } 42 | 43 | pub(crate) const fn u8usize(val: u8) -> usize { 44 | val as usize 45 | } 46 | 47 | pub(crate) const fn u16i32(val: u16) -> i32 { 48 | val as i32 49 | } 50 | 51 | pub(crate) const fn u16i64(val: u16) -> i64 { 52 | val as i64 53 | } 54 | 55 | pub(crate) const fn u16u32(val: u16) -> u32 { 56 | val as u32 57 | } 58 | 59 | pub(crate) const fn u32i64(val: u32) -> i64 { 60 | val as i64 61 | } 62 | -------------------------------------------------------------------------------- /wtx/src/tests.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | misc::UriString, 3 | rng::{Rng, Xorshift64, simple_seed}, 4 | sync::AtomicU32, 5 | }; 6 | use core::sync::atomic::Ordering; 7 | 8 | pub(crate) fn _uri() -> UriString { 9 | const INITIAL_PORT: u32 = 7000; 10 | #[cfg(all(feature = "loom", not(feature = "portable-atomic")))] 11 | let port = { 12 | static LOCKS: std::sync::OnceLock = std::sync::OnceLock::new(); 13 | &*LOCKS.get_or_init(|| AtomicU32::new(INITIAL_PORT)) 14 | }; 15 | #[cfg(any(not(feature = "loom"), feature = "portable-atomic"))] 16 | let port = { 17 | static PORT: AtomicU32 = AtomicU32::new(INITIAL_PORT); 18 | &PORT 19 | }; 20 | let uri = alloc::format!("http://127.0.0.1:{}", port.fetch_add(1, Ordering::Relaxed)); 21 | UriString::new(uri) 22 | } 23 | 24 | pub(crate) fn _32_bytes_seed() -> [u8; 32] { 25 | let seed = simple_seed(); 26 | let mut rng = Xorshift64::from(seed); 27 | let [a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0] = rng.u8_16(); 28 | let [a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1] = rng.u8_16(); 29 | [ 30 | a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, a1, b1, c1, d1, e1, f1, g1, h1, 31 | i1, j1, k1, l1, m1, n1, o1, p1, 32 | ] 33 | } 34 | -------------------------------------------------------------------------------- /wtx/src/grpc.rs: -------------------------------------------------------------------------------- 1 | //! gRPC (gRPC Remote Procedure Calls) is a high performance remote procedure call (RPC) 2 | //! framework. 3 | 4 | #[cfg(feature = "grpc-client")] 5 | mod grpc_client; 6 | mod grpc_manager; 7 | #[cfg(feature = "grpc-server")] 8 | mod grpc_middleware; 9 | mod grpc_status_code; 10 | 11 | use crate::{ 12 | collection::Vector, 13 | de::{ 14 | Encode, 15 | format::{De, EncodeWrapper}, 16 | }, 17 | }; 18 | 19 | #[cfg(feature = "grpc-client")] 20 | pub use grpc_client::GrpcClient; 21 | pub use grpc_manager::GrpcManager; 22 | #[cfg(feature = "grpc-server")] 23 | pub use grpc_middleware::GrpcMiddleware; 24 | pub use grpc_status_code::GrpcStatusCode; 25 | 26 | fn serialize(bytes: &mut Vector, data: T, _: &mut DRSR) -> crate::Result<()> 27 | where 28 | T: Encode>, 29 | { 30 | bytes.extend_from_copyable_slice(&[0; 5])?; 31 | let before_len = bytes.len(); 32 | data.encode(&mut EncodeWrapper::new(bytes))?; 33 | let after_len = bytes.len(); 34 | if let [_, a, b, c, d, ..] = bytes.as_mut() { 35 | let len = u32::try_from(after_len.wrapping_sub(before_len)).unwrap_or_default(); 36 | let [e, f, g, h] = len.to_be_bytes(); 37 | *a = e; 38 | *b = f; 39 | *c = g; 40 | *d = h; 41 | } 42 | Ok(()) 43 | } 44 | -------------------------------------------------------------------------------- /wtx/src/database/client/mysql/mysql_error.rs: -------------------------------------------------------------------------------- 1 | /// Error 2 | #[derive(Debug)] 3 | pub enum MysqlError { 4 | /// Invalid auth plugin bytes 5 | InvalidAuthPluginBytes, 6 | /// Invalid auth switch bytes 7 | InvalidAuthSwitchBytes, 8 | /// Invalid binary row bytes 9 | InvalidBinaryRowBytes, 10 | /// Invalid column bytes 11 | InvalidColumnBytes, 12 | /// Invalid connection bytes 13 | InvalidConnectionBytes, 14 | /// Invalid error packet response bytes 15 | InvalidErrPacketResBytes, 16 | /// Invalid handshake bytes 17 | InvalidHandshakeBytes, 18 | /// Invalid lenenc content bytes 19 | InvalidLenencBytes, 20 | /// Invalid lenenc bytes 21 | InvalidLenencContentBytes, 22 | /// Invalid OK bytes 23 | InvalidOkBytes, 24 | /// Invalid prepare bytes 25 | InvalidPrepareBytes, 26 | /// Invalid text row bytes 27 | InvalidTextRowBytes, 28 | /// Fetch command expected one result but got zero or more than one results 29 | NonSingleFetch, 30 | /// Unknown authentication method 31 | UnknownAuthPlugin, 32 | /// Unknown configuration parameter 33 | UnknownConfigurationParameter, 34 | /// Mysql server does not support SSL 35 | UnsupportedServerSsl, 36 | /// Payloads greater than (2^24 - 1) are unsupported 37 | UnsupportedPayloadLen, 38 | } 39 | -------------------------------------------------------------------------------- /wtx-macros/src/client_api_framework/contained_attrs.rs: -------------------------------------------------------------------------------- 1 | use syn::Attribute; 2 | 3 | pub(crate) trait ContainedAttrs { 4 | fn contained_attrs(&mut self) -> Option<&mut Vec>; 5 | } 6 | 7 | impl ContainedAttrs for syn::Item { 8 | fn contained_attrs(&mut self) -> Option<&mut Vec> { 9 | Some(match *self { 10 | Self::Const(ref mut item) => item.attrs.as_mut(), 11 | Self::Enum(ref mut item) => item.attrs.as_mut(), 12 | Self::ExternCrate(ref mut item) => item.attrs.as_mut(), 13 | Self::Fn(ref mut item) => item.attrs.as_mut(), 14 | Self::ForeignMod(ref mut item) => item.attrs.as_mut(), 15 | Self::Impl(ref mut item) => item.attrs.as_mut(), 16 | Self::Macro(ref mut item) => item.attrs.as_mut(), 17 | Self::Mod(ref mut item) => item.attrs.as_mut(), 18 | Self::Static(ref mut item) => item.attrs.as_mut(), 19 | Self::Struct(ref mut item) => item.attrs.as_mut(), 20 | Self::Trait(ref mut item) => item.attrs.as_mut(), 21 | Self::TraitAlias(ref mut item) => item.attrs.as_mut(), 22 | Self::Type(ref mut item) => item.attrs.as_mut(), 23 | Self::Union(ref mut item) => item.attrs.as_mut(), 24 | Self::Use(ref mut item) => item.attrs.as_mut(), 25 | _ => return None, 26 | }) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /.test-utils/migrations/1__initial/3__insert_author.sql: -------------------------------------------------------------------------------- 1 | -- wtx IN 2 | 3 | INSERT INTO author(id, first_name, last_name, email) VALUES 4 | ('1','Werner','Turcotte','bryce.wiza@example.com'), 5 | ('2','Issac','Schroeder','luisa01@example.com'), 6 | ('3','Lorenzo','Grant','granville.crist@example.com'), 7 | ('4','Leopoldo','Cartwright','kelsi79@example.org'), 8 | ('5','Melyssa','Wilkinson','modesto17@example.org'), 9 | ('6','Mack','Lubowitz','cayla14@example.net'), 10 | ('7','Gladys','Corkery','ebreitenberg@example.com'), 11 | ('8','Lizeth','Carroll','leopold52@example.com'), 12 | ('9','Morris','Becker','bhudson@example.com'), 13 | ('10','Samara','Tillman','stokes.leta@example.org'), 14 | ('11','Garfield','Friesen','ruthe36@example.org'), 15 | ('12','Brain','Dietrich','rickey.huel@example.com'), 16 | ('13','Nakia','Kreiger','madelynn.watsica@example.org'), 17 | ('14','Markus','Abernathy','kohler.steve@example.com'), 18 | ('15','Duncan','Hane','leffler.wendell@example.net'), 19 | ('16','Yasmeen','Bahringer','qcrona@example.com'), 20 | ('17','Grover','Cartwright','rcronin@example.net'), 21 | ('18','Sarah','Stokes','gavin.reinger@example.org'), 22 | ('19','Norwood','Hessel','torp.serena@example.org'), 23 | ('20','Carol','Fay','pacocha.ora@example.org'); 24 | 25 | -- wtx OUT 26 | 27 | DELETE FROM author; 28 | -------------------------------------------------------------------------------- /wtx-instances/database-examples/database-client-postgres.rs: -------------------------------------------------------------------------------- 1 | //! Demonstrates different interactions with a PostgreSQL database. 2 | 3 | extern crate tokio; 4 | extern crate wtx; 5 | extern crate wtx_instances; 6 | 7 | use wtx::{ 8 | database::{Executor as _, Record, Records}, 9 | misc::into_rslt, 10 | }; 11 | 12 | #[tokio::main] 13 | async fn main() -> wtx::Result<()> { 14 | let uri = "postgres://USER:PASSWORD@localhost/DATABASE"; 15 | let mut executor = wtx_instances::executor_postgres(uri).await?; 16 | executor 17 | .transaction(|this| async { 18 | this.execute_ignored("CREATE TABLE IF NOT EXISTS example(id INT, name VARCHAR)").await?; 19 | this 20 | .execute_stmt_none("INSERT INTO foo VALUES ($1, $2), ($3, $4)", (1u32, "one", 2u32, "two")) 21 | .await?; 22 | Ok(((), this)) 23 | }) 24 | .await?; 25 | let records = executor 26 | .execute_stmt_many("SELECT id, name FROM example", (), |_| Ok::<_, wtx::Error>(())) 27 | .await?; 28 | let record0 = into_rslt(records.get(0))?; 29 | let record1 = into_rslt(records.get(1))?; 30 | assert_eq!((record0.decode::<_, u32>(0)?, record0.decode::<_, &str>("name")?), (1, "one")); 31 | assert_eq!((record1.decode::<_, u32>("id")?, record1.decode::<_, &str>(1)?), (2, "two")); 32 | Ok(()) 33 | } 34 | -------------------------------------------------------------------------------- /wtx-instances/generic-examples/grpc-client.rs: -------------------------------------------------------------------------------- 1 | //! gRPC client that uses the structure definitions found in the `wtx_instances::grpc_bindings` 2 | //! module. 3 | 4 | extern crate tokio; 5 | extern crate wtx; 6 | extern crate wtx_instances; 7 | 8 | use std::borrow::Cow; 9 | use wtx::{ 10 | de::format::QuickProtobuf, 11 | grpc::GrpcClient, 12 | http::{ReqResBuffer, client_pool::ClientPoolBuilder}, 13 | }; 14 | use wtx_instances::grpc_bindings::wtx::{GenericRequest, GenericResponse}; 15 | 16 | #[tokio::main] 17 | async fn main() -> wtx::Result<()> { 18 | let rrb = ReqResBuffer::empty(); 19 | let uri_ref = rrb.uri.to_ref(); 20 | let pool = ClientPoolBuilder::tokio(1).build(); 21 | let mut guard = pool.lock(&uri_ref).await?; 22 | let mut client = GrpcClient::new(&mut guard.client, QuickProtobuf); 23 | let res = client 24 | .send_unary_req( 25 | GenericRequest { 26 | generic_request_field0: Cow::Borrowed(b"generic_request_value"), 27 | generic_request_field1: 123, 28 | }, 29 | rrb, 30 | "http://127.0.0.1:9000/wtx.GenericService/generic_method".into(), 31 | ) 32 | .await?; 33 | let generic_response: GenericResponse = client.des_from_res_bytes(&mut res.rrd.body.as_ref())?; 34 | println!("{generic_response:?}"); 35 | Ok(()) 36 | } 37 | -------------------------------------------------------------------------------- /wtx/src/de/protocol/graph_ql/graph_ql_error.rs: -------------------------------------------------------------------------------- 1 | use crate::collection::Vector; 2 | use alloc::{boxed::Box, string::String}; 3 | 4 | /// Segment of a `GraphQL` document. 5 | #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] 6 | #[cfg_attr(feature = "serde", serde(untagged))] 7 | #[derive(Debug)] 8 | pub enum GraphQlPathSegment { 9 | /// Represents a named field. 10 | Field(Box), 11 | /// Represents an index offset. 12 | Index(i32), 13 | } 14 | 15 | /// Line and column of a `GraphQL` document. 16 | #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] 17 | #[derive(Debug)] 18 | pub struct GraphQlLocation { 19 | /// Document column 20 | pub column: i32, 21 | /// Document line 22 | pub line: i32, 23 | } 24 | 25 | /// Describes an unsuccessful request. 26 | #[derive(Debug)] 27 | #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] 28 | pub struct GraphQlResponseError { 29 | /// Any user custom value. 30 | pub extensions: Option, 31 | /// List of columns and lines 32 | pub locations: Option>, 33 | /// Error describer 34 | pub message: String, 35 | /// Full path to the result field where the error was raised. 36 | pub path: Option>, 37 | } 38 | -------------------------------------------------------------------------------- /wtx/src/http/request.rs: -------------------------------------------------------------------------------- 1 | use crate::http::{Method, ReqResDataMut, Response, StatusCode, Version}; 2 | 3 | /// An HTTP request received by a server or to be sent by a client. 4 | #[derive(Debug)] 5 | pub struct Request { 6 | /// See [`Method`]. 7 | pub method: Method, 8 | /// See [`crate::http::ReqResData`]. 9 | pub rrd: RRD, 10 | /// See [`Version`]. 11 | pub version: Version, 12 | } 13 | 14 | impl Request { 15 | /// Constructor shortcut 16 | #[inline] 17 | pub const fn new(method: Method, rrd: RRD, version: Version) -> Self { 18 | Self { method, rrd, version } 19 | } 20 | 21 | /// Constructor that defaults to an HTTP/2 version. 22 | #[inline] 23 | pub const fn http2(method: Method, rrd: RRD) -> Self { 24 | Self { method, rrd, version: Version::Http2 } 25 | } 26 | 27 | /// Creates a new [`Response`] using the inner buffer as well as the given `status_code`. 28 | #[inline] 29 | pub fn into_response(self, status_code: StatusCode) -> Response { 30 | Response { rrd: self.rrd, status_code, version: self.version } 31 | } 32 | } 33 | 34 | impl Request 35 | where 36 | RRD: ReqResDataMut, 37 | { 38 | /// Clear body and header contents 39 | #[inline] 40 | pub fn clear(&mut self) { 41 | self.rrd.clear(); 42 | } 43 | } 44 | --------------------------------------------------------------------------------