0.1.0
This commit is contained in:
42
.gitignore
vendored
Normal file
42
.gitignore
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
Cargo.lock
|
||||
/target/
|
||||
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
|
||||
# mails
|
||||
*.eml
|
||||
# Node
|
||||
node_modules
|
||||
package-lock.json
|
||||
dist
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
.settings
|
||||
.project
|
||||
|
||||
# PID
|
||||
*.pid
|
||||
|
||||
# var folder
|
||||
var/
|
||||
# env
|
||||
.env
|
||||
!.env.dev
|
||||
config.json
|
||||
|
||||
# sqlite
|
||||
*.db
|
||||
*.db-shm
|
||||
*.db-wal
|
||||
47
Cargo.toml
Normal file
47
Cargo.toml
Normal file
@@ -0,0 +1,47 @@
|
||||
# file: Cargo.toml
|
||||
|
||||
[workspace]
|
||||
resolver = "3"
|
||||
members = [
|
||||
"khbb_lib",
|
||||
"khbb_listener_app",
|
||||
]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
license = "MIT"
|
||||
repository = "https://git.sasedev.com/Sasedev/khadhroony-bobot"
|
||||
authors = ["SinuS von SifriduS <sinus@sasedev.net>"]
|
||||
publish = false
|
||||
|
||||
[workspace.dependencies]
|
||||
async-trait = { version = "^0.1", features = [] }
|
||||
base64 = { version = "^0.22", features = [] }
|
||||
chrono = { version = "^0.4", features = ["serde"] }
|
||||
futures-util = { version = "^0.3", features = [] }
|
||||
reqwest = { version = "^0.13", default-features = false, features = ["charset", "cookies", "deflate", "form", "gzip", "http2", "json", "multipart", "query", "rustls", "socks", "stream", "zstd"] }
|
||||
rustls = { version = "^0.23", features = ["aws-lc-rs"] }
|
||||
serde = { version = "^1.0", features = ["derive"] }
|
||||
serde_json = { version = "^1.0", features = [] }
|
||||
solana-account-decoder-client-types = { version = "4.0.0-beta.7", features = ["zstd"] }
|
||||
solana-address-lookup-table-interface = { version = "^3.0", features = ["bincode", "serde"] }
|
||||
solana-client = { version = "^3.1", features = [] }
|
||||
solana-compute-budget-interface = { version = "^3.0", features = ["borsh", "serde"] }
|
||||
solana-rpc-client-api = { version = "4.0.0-beta.7", features = [] }
|
||||
solana-sdk = { version = "^4.0", features = ["full"] }
|
||||
solana-sdk-ids = { version = "^3.1", features = [] }
|
||||
solana-system-interface = { version = "^3.0", features = ["alloc", "bincode", "serde", "std"] }
|
||||
solana-transaction-status-client-types = { version = "4.0.0-beta.7", features = [] }
|
||||
spl-associated-token-account-interface = { version = "^2.0", features = ["borsh"] }
|
||||
spl-memo-interface = { version = "^2.0", features = [] }
|
||||
spl-token-interface = { version = "^2.0", features = [] }
|
||||
spl-token-2022-interface = { version = "^2.1", features = [] }
|
||||
sqlx = { version = "^0.8", features = ["chrono", "uuid", "bigdecimal", "json", "sqlite", "runtime-tokio-rustls"] }
|
||||
tokio = { version = "^1.52", features = ["full"] }
|
||||
tokio-stream = { version = "^0.1", features = ["full"] }
|
||||
tokio-tungstenite = { version = "^0.29", default-features = false, features = ["connect", "handshake", "rustls-tls-webpki-roots", "stream", "url"] }
|
||||
tracing = { version = "^0.1", features = [] }
|
||||
tracing-subscriber = { version = "^0.3", features = ["ansi", "env-filter", "chrono", "serde", "json"] }
|
||||
yellowstone-grpc-client = { version = "^13.0", features = [] }
|
||||
yellowstone-grpc-proto = { version = "^12.2", features = [] }
|
||||
34
clippy.toml
Normal file
34
clippy.toml
Normal file
@@ -0,0 +1,34 @@
|
||||
# file: clippy.toml
|
||||
|
||||
msrv = "1.85.0"
|
||||
|
||||
# The project favors explicit control flow and visible intent.
|
||||
# These settings complement the coding rules already enforced manually
|
||||
# in code review: no `?`, no `unwrap`, no `expect`, explicit error paths.
|
||||
|
||||
too-many-arguments-threshold = 8
|
||||
type-complexity-threshold = 250
|
||||
single-char-binding-names-threshold = 3
|
||||
trivial-copy-size-limit = 16
|
||||
pass-by-value-size-limit = 256
|
||||
stack-size-threshold = 512000
|
||||
vec-box-size-threshold = 4096
|
||||
max-fn-params-bools = 2
|
||||
max-include-file-size = 1048576
|
||||
cognitive-complexity-threshold = 25
|
||||
too-large-for-stack = 2048
|
||||
enum-variant-size-threshold = 200
|
||||
large-error-threshold = 128
|
||||
avoid-breaking-exported-api = true
|
||||
disallowed-macros = []
|
||||
disallowed-methods = []
|
||||
disallowed-names = ["foo", "bar", "baz", "tmp"]
|
||||
disallowed-types = []
|
||||
allowed-idents-below-min-chars = [
|
||||
"id",
|
||||
"tx",
|
||||
"rx",
|
||||
"ms",
|
||||
"pcm",
|
||||
"vad",
|
||||
]
|
||||
40
khbb_lib/Cargo.toml
Normal file
40
khbb_lib/Cargo.toml
Normal file
@@ -0,0 +1,40 @@
|
||||
# file: khbb_lib/Cargo.toml
|
||||
|
||||
[package]
|
||||
name = "khbb_lib"
|
||||
edition.workspace = true
|
||||
version.workspace = true
|
||||
license.workspace = true
|
||||
authors.workspace = true
|
||||
publish.workspace = true
|
||||
|
||||
[dependencies]
|
||||
async-trait.workspace = true
|
||||
base64.workspace = true
|
||||
chrono.workspace = true
|
||||
futures-util.workspace = true
|
||||
reqwest.workspace = true
|
||||
rustls.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
solana-account-decoder-client-types.workspace = true
|
||||
solana-address-lookup-table-interface.workspace = true
|
||||
solana-client.workspace = true
|
||||
solana-compute-budget-interface.workspace = true
|
||||
solana-rpc-client-api.workspace = true
|
||||
solana-sdk.workspace = true
|
||||
solana-sdk-ids.workspace = true
|
||||
solana-system-interface.workspace = true
|
||||
solana-transaction-status-client-types.workspace = true
|
||||
spl-associated-token-account-interface.workspace = true
|
||||
spl-memo-interface.workspace = true
|
||||
spl-token-2022-interface.workspace = true
|
||||
spl-token-interface.workspace = true
|
||||
sqlx.workspace = true
|
||||
tokio.workspace = true
|
||||
tokio-stream.workspace = true
|
||||
tokio-tungstenite.workspace = true
|
||||
tracing.workspace = true
|
||||
tracing-subscriber.workspace = true
|
||||
yellowstone-grpc-client.workspace = true
|
||||
yellowstone-grpc-proto.workspace = true
|
||||
33
khbb_lib/README.md
Normal file
33
khbb_lib/README.md
Normal file
@@ -0,0 +1,33 @@
|
||||
<!-- file: khbb_lib/README.md -->
|
||||
|
||||
# khbb_lib
|
||||
|
||||
Core library for the `khadhroony-bobot` workspace.
|
||||
|
||||
## Goals
|
||||
|
||||
- centralize reusable logic
|
||||
- expose explicit APIs to binaries
|
||||
- provide Solana RPC HTTP / WS / gRPC integrations
|
||||
- provide storage and domain layers
|
||||
- avoid hidden logic in binaries
|
||||
|
||||
## Rules
|
||||
|
||||
- no `anyhow`
|
||||
- no `thiserror`
|
||||
- no `?`
|
||||
- no `unwrap` / `expect`
|
||||
- explicit error handling
|
||||
- async first
|
||||
- `tracing`
|
||||
- no `mod.rs`
|
||||
- no `pub mod`
|
||||
- `pub use` only from `lib.rs`
|
||||
|
||||
## Initial scope
|
||||
|
||||
- config loading
|
||||
- tracing initialization
|
||||
- SQLite connectivity
|
||||
- listener runtime bootstrap
|
||||
22
khbb_lib/TODO.md
Normal file
22
khbb_lib/TODO.md
Normal file
@@ -0,0 +1,22 @@
|
||||
<!-- file: khbb_lib/TODO.md -->
|
||||
|
||||
# khbb_lib TODO
|
||||
|
||||
## Foundation
|
||||
|
||||
- [x] create public library entrypoint
|
||||
- [x] create explicit error type
|
||||
- [x] create config loader
|
||||
- [x] create tracing bootstrap
|
||||
- [x] create listener app runner
|
||||
|
||||
## Next
|
||||
|
||||
- [ ] add storage layer
|
||||
- [ ] add SQLite schema bootstrap
|
||||
- [ ] add HTTP RPC client layer based on `reqwest`
|
||||
- [ ] add WebSocket RPC client layer based on `tokio-tungstenite`
|
||||
- [ ] add Yellowstone gRPC client layer
|
||||
- [ ] add event normalization types
|
||||
- [ ] add listener orchestration
|
||||
- [ ] add tests
|
||||
59
khbb_lib/src/app.rs
Normal file
59
khbb_lib/src/app.rs
Normal file
@@ -0,0 +1,59 @@
|
||||
// file: khbb_lib/src/app.rs
|
||||
|
||||
/// Runs the initial listener application workflow.
|
||||
///
|
||||
/// This first version only:
|
||||
/// - loads configuration
|
||||
/// - opens the SQLite connection pool
|
||||
/// - verifies connectivity
|
||||
/// - keeps the runtime alive as the future integration point for listener tasks
|
||||
pub async fn run_listener_app(config_path: &str) -> core::result::Result<(), crate::KhbbError> {
|
||||
let config_result = crate::KhbbAppConfig::load_from_json_file(config_path).await;
|
||||
let config = match config_result {
|
||||
Ok(value) => value,
|
||||
Err(error) => {
|
||||
return Err(error);
|
||||
},
|
||||
};
|
||||
let tracing_result = crate::init_tracing(&config.log_filter);
|
||||
match tracing_result {
|
||||
Ok(()) => {},
|
||||
Err(error) => {
|
||||
return Err(error);
|
||||
},
|
||||
}
|
||||
tracing::info!(
|
||||
database_url = %config.database_url,
|
||||
solana_http_rpc_url = %config.solana_http_rpc_url,
|
||||
solana_ws_rpc_url = %config.solana_ws_rpc_url,
|
||||
yellowstone_grpc_url = ?config.yellowstone_grpc_url,
|
||||
"khbb listener app starting"
|
||||
);
|
||||
let connect_result = sqlx::sqlite::SqlitePoolOptions::new()
|
||||
.max_connections(1)
|
||||
.connect(&config.database_url)
|
||||
.await;
|
||||
let pool = match connect_result {
|
||||
Ok(value) => value,
|
||||
Err(error) => {
|
||||
return Err(crate::KhbbError::Database {
|
||||
context: "connect sqlite pool",
|
||||
message: error.to_string(),
|
||||
});
|
||||
},
|
||||
};
|
||||
let ping_result = sqlx::query("SELECT 1;").execute(&pool).await;
|
||||
match ping_result {
|
||||
Ok(_) => {
|
||||
tracing::info!("sqlite connectivity check succeeded");
|
||||
},
|
||||
Err(error) => {
|
||||
return Err(crate::KhbbError::Database {
|
||||
context: "ping sqlite database",
|
||||
message: error.to_string(),
|
||||
});
|
||||
},
|
||||
}
|
||||
tracing::info!("listener tasks are not wired yet");
|
||||
Ok(())
|
||||
}
|
||||
71
khbb_lib/src/config.rs
Normal file
71
khbb_lib/src/config.rs
Normal file
@@ -0,0 +1,71 @@
|
||||
// file: khbb_lib/src/config.rs
|
||||
|
||||
/// Root application configuration used by the initial listener stack.
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub struct KhbbAppConfig {
|
||||
/// Path or URL to the SQLite database.
|
||||
pub database_url: std::string::String,
|
||||
/// Solana HTTP RPC endpoint.
|
||||
pub solana_http_rpc_url: std::string::String,
|
||||
/// Solana WebSocket RPC endpoint.
|
||||
pub solana_ws_rpc_url: std::string::String,
|
||||
/// Optional Yellowstone gRPC endpoint.
|
||||
pub yellowstone_grpc_url: std::option::Option<std::string::String>,
|
||||
/// Tracing filter string.
|
||||
pub log_filter: std::string::String,
|
||||
}
|
||||
|
||||
impl KhbbAppConfig {
|
||||
/// Loads the application configuration from a JSON file.
|
||||
pub async fn load_from_json_file(path: &str) -> core::result::Result<Self, crate::KhbbError> {
|
||||
let file_content_result = tokio::fs::read_to_string(path).await;
|
||||
let file_content = match file_content_result {
|
||||
Ok(value) => value,
|
||||
Err(error) => {
|
||||
return Err(crate::KhbbError::Io {
|
||||
context: "read config file",
|
||||
message: error.to_string(),
|
||||
});
|
||||
},
|
||||
};
|
||||
let parse_result = serde_json::from_str::<Self>(&file_content);
|
||||
let config = match parse_result {
|
||||
Ok(value) => value,
|
||||
Err(error) => {
|
||||
return Err(crate::KhbbError::Json {
|
||||
context: "parse config json",
|
||||
message: error.to_string(),
|
||||
});
|
||||
},
|
||||
};
|
||||
let validate_result = config.validate();
|
||||
match validate_result {
|
||||
Ok(()) => Ok(config),
|
||||
Err(error) => Err(error),
|
||||
}
|
||||
}
|
||||
/// Validates the application configuration.
|
||||
pub fn validate(&self) -> core::result::Result<(), crate::KhbbError> {
|
||||
if self.database_url.trim().is_empty() {
|
||||
return Err(crate::KhbbError::Config {
|
||||
message: std::string::String::from("database_url must not be empty"),
|
||||
});
|
||||
}
|
||||
if self.solana_http_rpc_url.trim().is_empty() {
|
||||
return Err(crate::KhbbError::Config {
|
||||
message: std::string::String::from("solana_http_rpc_url must not be empty"),
|
||||
});
|
||||
}
|
||||
if self.solana_ws_rpc_url.trim().is_empty() {
|
||||
return Err(crate::KhbbError::Config {
|
||||
message: std::string::String::from("solana_ws_rpc_url must not be empty"),
|
||||
});
|
||||
}
|
||||
if self.log_filter.trim().is_empty() {
|
||||
return Err(crate::KhbbError::Config {
|
||||
message: std::string::String::from("log_filter must not be empty"),
|
||||
});
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
76
khbb_lib/src/error.rs
Normal file
76
khbb_lib/src/error.rs
Normal file
@@ -0,0 +1,76 @@
|
||||
// file: khbb_lib/src/error.rs
|
||||
|
||||
/// Main error type used across the khbb workspace.
|
||||
///
|
||||
/// This project intentionally uses a single explicit error enum instead of
|
||||
/// `anyhow` or `thiserror`.
|
||||
#[derive(Debug)]
|
||||
pub enum KhbbError {
|
||||
/// Returned when a filesystem operation fails.
|
||||
Io {
|
||||
/// Human-readable operation label.
|
||||
context: &'static str,
|
||||
/// Source message.
|
||||
message: std::string::String,
|
||||
},
|
||||
/// Returned when JSON decoding or encoding fails.
|
||||
Json {
|
||||
/// Human-readable operation label.
|
||||
context: &'static str,
|
||||
/// Source message.
|
||||
message: std::string::String,
|
||||
},
|
||||
/// Returned when configuration validation fails.
|
||||
Config {
|
||||
/// Validation message.
|
||||
message: std::string::String,
|
||||
},
|
||||
/// Returned when SQLx operations fail.
|
||||
Database {
|
||||
/// Human-readable operation label.
|
||||
context: &'static str,
|
||||
/// Source message.
|
||||
message: std::string::String,
|
||||
},
|
||||
/// Returned when tracing initialization fails.
|
||||
Tracing {
|
||||
/// Human-readable operation label.
|
||||
context: &'static str,
|
||||
/// Source message.
|
||||
message: std::string::String,
|
||||
},
|
||||
/// Returned when a runtime task fails.
|
||||
Runtime {
|
||||
/// Human-readable operation label.
|
||||
context: &'static str,
|
||||
/// Source message.
|
||||
message: std::string::String,
|
||||
},
|
||||
}
|
||||
|
||||
impl core::fmt::Display for KhbbError {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
match self {
|
||||
Self::Io { context, message } => {
|
||||
write!(f, "io error during {context}: {message}")
|
||||
},
|
||||
Self::Json { context, message } => {
|
||||
write!(f, "json error during {context}: {message}")
|
||||
},
|
||||
Self::Config { message } => {
|
||||
write!(f, "configuration error: {message}")
|
||||
},
|
||||
Self::Database { context, message } => {
|
||||
write!(f, "database error during {context}: {message}")
|
||||
},
|
||||
Self::Tracing { context, message } => {
|
||||
write!(f, "tracing error during {context}: {message}")
|
||||
},
|
||||
Self::Runtime { context, message } => {
|
||||
write!(f, "runtime error during {context}: {message}")
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for KhbbError {}
|
||||
23
khbb_lib/src/lib.rs
Normal file
23
khbb_lib/src/lib.rs
Normal file
@@ -0,0 +1,23 @@
|
||||
// file: khbb_lib/src/lib.rs
|
||||
|
||||
//! Core public library for the `khadhroony-bobot` workspace.
|
||||
//!
|
||||
//! This crate exposes the reusable building blocks shared by the khbb
|
||||
//! applications, starting with the listener runtime bootstrap.
|
||||
|
||||
#![deny(unreachable_pub)]
|
||||
#![warn(missing_docs)]
|
||||
|
||||
mod app;
|
||||
mod config;
|
||||
mod error;
|
||||
mod tracing_setup;
|
||||
|
||||
/// Public re-exports for the khbb core library.
|
||||
pub use crate::app::run_listener_app;
|
||||
/// Public re-exports for configuration loading.
|
||||
pub use crate::config::KhbbAppConfig;
|
||||
/// Public re-exports for configuration loading errors and runtime errors.
|
||||
pub use crate::error::KhbbError;
|
||||
/// Public re-exports for tracing initialization.
|
||||
pub use crate::tracing_setup::init_tracing;
|
||||
31
khbb_lib/src/tracing_setup.rs
Normal file
31
khbb_lib/src/tracing_setup.rs
Normal file
@@ -0,0 +1,31 @@
|
||||
// file: khbb_lib/src/tracing_setup.rs
|
||||
|
||||
/// Initializes tracing subscribers for the application.
|
||||
pub fn init_tracing(log_filter: &str) -> core::result::Result<(), crate::KhbbError> {
|
||||
let env_filter_result =
|
||||
tracing_subscriber::EnvFilter::try_new(std::string::String::from(log_filter));
|
||||
let env_filter = match env_filter_result {
|
||||
Ok(value) => value,
|
||||
Err(error) => {
|
||||
return Err(crate::KhbbError::Tracing {
|
||||
context: "build env filter",
|
||||
message: error.to_string(),
|
||||
});
|
||||
},
|
||||
};
|
||||
let subscriber = tracing_subscriber::fmt()
|
||||
.with_env_filter(env_filter)
|
||||
.with_target(true)
|
||||
.with_thread_ids(true)
|
||||
.with_thread_names(true)
|
||||
.with_ansi(true)
|
||||
.finish();
|
||||
let set_result = tracing::subscriber::set_global_default(subscriber);
|
||||
match set_result {
|
||||
Ok(()) => Ok(()),
|
||||
Err(error) => Err(crate::KhbbError::Tracing {
|
||||
context: "set global subscriber",
|
||||
message: error.to_string(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
14
khbb_listener_app/Cargo.toml
Normal file
14
khbb_listener_app/Cargo.toml
Normal file
@@ -0,0 +1,14 @@
|
||||
# file: khbb_listener_app/Cargo.toml
|
||||
|
||||
[package]
|
||||
name = "khbb_listener_app"
|
||||
edition.workspace = true
|
||||
version.workspace = true
|
||||
license.workspace = true
|
||||
authors.workspace = true
|
||||
publish.workspace = true
|
||||
|
||||
[dependencies]
|
||||
khbb_lib = { path = "../khbb_lib" }
|
||||
tokio.workspace = true
|
||||
tracing.workspace = true
|
||||
15
khbb_listener_app/README.md
Normal file
15
khbb_listener_app/README.md
Normal file
@@ -0,0 +1,15 @@
|
||||
<!-- file: khbb_listener_app/README.md -->
|
||||
|
||||
# khbb_listener_app
|
||||
|
||||
Listener binary for the `khadhroony-bobot` workspace.
|
||||
|
||||
## Role
|
||||
|
||||
This binary starts the listener runtime and delegates all logic to `khbb_lib`.
|
||||
|
||||
## Current state
|
||||
|
||||
- reads `config.json` by default
|
||||
- accepts an optional config path as first CLI argument
|
||||
- initializes the runtime through `khbb_lib`
|
||||
9
khbb_listener_app/TODO.md
Normal file
9
khbb_listener_app/TODO.md
Normal file
@@ -0,0 +1,9 @@
|
||||
<!-- file: khbb_listener_app/TODO.md -->
|
||||
|
||||
# khbb_listener_app TODO
|
||||
|
||||
- [x] create thin binary entrypoint
|
||||
- [x] delegate startup to `khbb_lib`
|
||||
- [ ] add clean shutdown handling
|
||||
- [ ] add signal handling
|
||||
- [ ] add richer CLI options later if needed
|
||||
26
khbb_listener_app/src/main.rs
Normal file
26
khbb_listener_app/src/main.rs
Normal file
@@ -0,0 +1,26 @@
|
||||
// file: khbb_listener_app/src/main.rs
|
||||
|
||||
//! Binary entrypoint for the khbb listener application.
|
||||
//!
|
||||
//! This binary remains intentionally thin and delegates its logic to `khbb_lib`.
|
||||
|
||||
#![deny(unreachable_pub)]
|
||||
#![warn(missing_docs)]
|
||||
|
||||
/// Entrypoint of the khbb listener binary.
|
||||
///
|
||||
/// This binary is intentionally thin and delegates all business logic to
|
||||
/// `khbb_lib`.
|
||||
#[tokio::main]
|
||||
async fn main() -> std::process::ExitCode {
|
||||
let args = std::env::args().collect::<std::vec::Vec<std::string::String>>();
|
||||
let config_path = if args.len() >= 2 { args[1].as_str() } else { "config.json" };
|
||||
let run_result = khbb_lib::run_listener_app(config_path).await;
|
||||
match run_result {
|
||||
Ok(()) => std::process::ExitCode::SUCCESS,
|
||||
Err(error) => {
|
||||
eprintln!("khbb_listener_app failed: {error}");
|
||||
std::process::ExitCode::FAILURE
|
||||
},
|
||||
}
|
||||
}
|
||||
38
rustfmt.toml
Normal file
38
rustfmt.toml
Normal file
@@ -0,0 +1,38 @@
|
||||
# file: rustfmt.toml
|
||||
|
||||
edition = "2024"
|
||||
newline_style = "Unix"
|
||||
use_small_heuristics = "Default"
|
||||
hard_tabs = false
|
||||
tab_spaces = 4
|
||||
max_width = 100
|
||||
chain_width = 80
|
||||
fn_call_width = 80
|
||||
attr_fn_like_width = 80
|
||||
struct_lit_width = 40
|
||||
struct_variant_width = 40
|
||||
array_width = 80
|
||||
single_line_if_else_max_width = 80
|
||||
single_line_let_else_max_width = 80
|
||||
imports_indent = "Block"
|
||||
group_imports = "StdExternalCrate"
|
||||
imports_granularity = "Module"
|
||||
reorder_imports = true
|
||||
reorder_modules = true
|
||||
normalize_comments = false
|
||||
normalize_doc_attributes = false
|
||||
format_code_in_doc_comments = false
|
||||
wrap_comments = false
|
||||
format_strings = false
|
||||
hex_literal_case = "Lower"
|
||||
empty_item_single_line = true
|
||||
struct_field_align_threshold = 0
|
||||
enum_discrim_align_threshold = 0
|
||||
match_arm_blocks = true
|
||||
match_block_trailing_comma = true
|
||||
trailing_comma = "Vertical"
|
||||
use_field_init_shorthand = true
|
||||
use_try_shorthand = false
|
||||
force_explicit_abi = true
|
||||
condense_wildcard_suffixes = false
|
||||
unstable_features = false
|
||||
Reference in New Issue
Block a user