1#[cfg(doctest)]
33#[doc = include_str!("../README.md")]
34struct ReadmeDoctests;
35
36#[macro_use]
37pub mod macros;
38
39pub mod auth;
40pub mod client;
41pub mod error;
42pub mod rate_limit;
43pub mod request;
44pub mod signer_limit;
45
46#[cfg(feature = "keychain")]
47pub mod keychain;
48
49const LOG_BODY_MAX_LEN: usize = 512;
51
52pub fn truncate_for_log(s: &str) -> std::borrow::Cow<'_, str> {
57 if s.len() <= LOG_BODY_MAX_LEN {
58 std::borrow::Cow::Borrowed(s)
59 } else {
60 let truncated = &s[..s.floor_char_boundary(LOG_BODY_MAX_LEN)];
61 std::borrow::Cow::Owned(format!("{}... [truncated]", truncated))
62 }
63}
64
65pub use auth::{current_timestamp, Base64Format, Signer};
66pub use client::{
67 retry_after_header, HttpClient, HttpClientBuilder, DEFAULT_POOL_SIZE, DEFAULT_TIMEOUT_MS,
68};
69pub use error::ApiError;
70pub use rate_limit::{RateLimiter, RetryConfig};
71pub use request::{QueryBuilder, Request, RequestError};
72pub use signer_limit::{
73 BurstCapacityExceeded, RateLimitStatus, SignerLimiter, Tier, TradingBucket, TradingRequest,
74};
75
76#[cfg(feature = "keychain")]
77pub use keychain::KeychainError;
78
79#[cfg(test)]
80mod tests {
81 use super::*;
82
83 #[test]
84 fn test_truncate_for_log_short_string_unchanged() {
85 let short = "hello world";
86 let result = truncate_for_log(short);
87 assert_eq!(result.as_ref(), short);
88 }
89
90 #[test]
91 fn test_truncate_for_log_exact_limit_unchanged() {
92 let exact = "a".repeat(LOG_BODY_MAX_LEN);
93 let result = truncate_for_log(&exact);
94 assert_eq!(result.as_ref(), exact.as_str());
95 }
96
97 #[test]
98 fn test_truncate_for_log_over_limit_truncated() {
99 let long = "x".repeat(LOG_BODY_MAX_LEN + 100);
100 let result = truncate_for_log(&long);
101 assert!(result.ends_with("... [truncated]"));
102 assert!(result.len() < long.len());
103 }
104
105 #[test]
106 fn test_truncate_for_log_multibyte_char_boundary() {
107 let mut s = "a".repeat(LOG_BODY_MAX_LEN - 1);
109 s.push('\u{1F600}'); s.push_str("overflow");
111 let result = truncate_for_log(&s);
112 assert!(result.ends_with("... [truncated]"));
113 assert!(result.is_char_boundary(0));
115 }
116}