1#![no_std]
51#![cfg_attr(docsrs, feature(doc_cfg))]
52#![allow(clippy::arithmetic_side_effects)]
53
54pub mod logger;
55mod wrapper;
56
57#[cfg(feature = "macro")]
58#[doc(hidden)]
59pub mod __macro_reexports {
60 pub use solana_program_log_macro::log;
61}
62
63#[cfg(feature = "macro")]
64pub use solana_program_log_macro::log_cu_usage;
65
66#[cfg(feature = "macro")]
67#[macro_export]
136macro_rules! log {
137 ( $len:literal, $message:literal $(, $args:expr )* $(,)? ) => {
138 $crate::__macro_reexports::log!($crate, $len, $message $(, $args )*)
139 };
140 ( $message:literal $(, $args:expr )* $(,)? ) => {
141 $crate::__macro_reexports::log!($crate, $message $(, $args )*)
142 };
143}
144
145pub use {
146 logger::{Argument, Logger},
147 wrapper::*,
148};
149
150#[cfg(all(not(any(target_os = "solana", target_arch = "bpf")), feature = "std"))]
153extern crate std;
154
155#[cfg(test)]
156mod tests {
157 use super::{Argument, Logger};
158
159 macro_rules! generate_numeric_test_case {
165 ( $value:expr, $max_len:expr, $($size:expr),+ $(,)? ) => {
166 $(
167 let mut logger = Logger::<$size>::default();
168 logger.append($value);
169 assert!((*logger).len() <= $max_len);
170 )*
171 };
172 }
173
174 macro_rules! generate_str_test_case {
180 ( $str:expr, $($size:expr),+ $(,)? ) => {
181 $(
182 let mut logger = Logger::<$size>::default();
183 logger.append(core::str::from_utf8($str).unwrap());
184 assert_eq!((*logger).len(), core::cmp::min($str.len(), $size));
185 )*
186 };
187 }
188
189 #[test]
190 fn test_logger() {
191 let mut logger = Logger::<100>::default();
192 logger.append("Hello ");
193 logger.append("world!");
194
195 assert!(&*logger == "Hello world!".as_bytes());
196
197 logger.clear();
198
199 logger.append("balance=");
200 logger.append(1_000_000_000);
201
202 assert!(&*logger == "balance=1000000000".as_bytes());
203 }
204
205 #[test]
206 fn test_logger_truncated() {
207 let mut logger = Logger::<8>::default();
208 logger.append("Hello ");
209 logger.append("world!");
210
211 assert!(&*logger == "Hello w@".as_bytes());
212
213 let mut logger = Logger::<12>::default();
214
215 logger.append("balance=");
216 logger.append(1_000_000_000);
217
218 assert!(&*logger == "balance=100@".as_bytes());
219 }
220
221 #[test]
222 fn test_logger_slice() {
223 let mut logger = Logger::<20>::default();
224 logger.append(&["Hello ", "world!"]);
225
226 assert!(&*logger == "[\"Hello \", \"world!\"]".as_bytes());
227
228 let mut logger = Logger::<20>::default();
229 logger.append(&[123, 456]);
230
231 assert!(&*logger == "[123, 456]".as_bytes());
232 }
233
234 #[test]
235 fn test_logger_truncated_slice() {
236 let mut logger = Logger::<5>::default();
237 logger.append(&["Hello ", "world!"]);
238
239 assert!(&*logger == "[\"He@".as_bytes());
240
241 let mut logger = Logger::<4>::default();
242 logger.append(&[123, 456]);
243
244 assert!(&*logger == "[12@".as_bytes());
245 }
246
247 #[test]
248 fn test_logger_signed() {
249 let mut logger = Logger::<2>::default();
250 logger.append(-2);
251
252 assert!(&*logger == "-2".as_bytes());
253
254 let mut logger = Logger::<5>::default();
255 logger.append(-200_000_000);
256
257 assert!(&*logger == "-200@".as_bytes());
258 }
259
260 #[test]
261 fn test_logger_with_precision() {
262 let mut logger = Logger::<10>::default();
263
264 logger.append_with_args(200_000_000u64, &[Argument::Precision(2)]);
265 assert!(&*logger == "2000000.00".as_bytes());
266
267 logger.clear();
268
269 logger.append_with_args(2_000_000_000u64, &[Argument::Precision(2)]);
270 assert!(&*logger == "20000000.@".as_bytes());
271
272 logger.clear();
273
274 logger.append_with_args(2_000_000_000u64, &[Argument::Precision(5)]);
275 assert!(&*logger == "20000.000@".as_bytes());
276
277 logger.clear();
278
279 logger.append_with_args(2_000_000_000u64, &[Argument::Precision(10)]);
280 assert!(&*logger == "0.2000000@".as_bytes());
281
282 logger.clear();
283
284 logger.append_with_args(2u64, &[Argument::Precision(6)]);
285 assert!(&*logger == "0.000002".as_bytes());
286
287 logger.clear();
288
289 logger.append_with_args(2u64, &[Argument::Precision(9)]);
290 assert!(&*logger == "0.0000000@".as_bytes());
291
292 logger.clear();
293
294 logger.append_with_args(-2000000i32, &[Argument::Precision(6)]);
295 assert!(&*logger == "-2.000000".as_bytes());
296
297 logger.clear();
298
299 logger.append_with_args(-2i64, &[Argument::Precision(9)]);
300 assert!(&*logger == "-0.000000@".as_bytes());
301
302 logger.clear();
303
304 logger.append_with_args("0123456789", &[Argument::Precision(2)]);
306 assert!(&*logger == "0123456789".as_bytes());
307
308 logger.clear();
309
310 logger.append_with_args(2u8, &[Argument::Precision(8)]);
311 assert!(&*logger == "0.00000002".as_bytes());
312
313 logger.clear();
314
315 logger.append_with_args(2u8, &[Argument::Precision(u8::MAX)]);
316 assert!(&*logger == "0.0000000@".as_bytes());
317
318 let mut logger = Logger::<20>::default();
319
320 logger.append_with_args(2u8, &[Argument::Precision(u8::MAX)]);
321 assert!(&*logger == "0.00000000000000000@".as_bytes());
322
323 logger.clear();
324
325 logger.append_with_args(20_000u16, &[Argument::Precision(10)]);
326 assert!(&*logger == "0.0000020000".as_bytes());
327
328 let mut logger = Logger::<3>::default();
329
330 logger.append_with_args(2u64, &[Argument::Precision(u8::MAX)]);
331 assert!(&*logger == "0.@".as_bytes());
332
333 logger.clear();
334
335 logger.append_with_args(2u64, &[Argument::Precision(1)]);
336 assert!(&*logger == "0.2".as_bytes());
337
338 logger.clear();
339
340 logger.append_with_args(-2i64, &[Argument::Precision(1)]);
341 assert!(&*logger == "-0@".as_bytes());
342
343 let mut logger = Logger::<1>::default();
344
345 logger.append_with_args(-2i64, &[Argument::Precision(1)]);
346 assert!(&*logger == "@".as_bytes());
347
348 let mut logger = Logger::<2>::default();
349
350 logger.append_with_args(-2i64, &[Argument::Precision(1)]);
351 assert!(&*logger == "-@".as_bytes());
352
353 let mut logger = Logger::<20>::default();
354
355 logger.append_with_args(u64::MAX, &[Argument::Precision(u8::MAX)]);
356 assert!(&*logger == "0.00000000000000000@".as_bytes());
357
358 let mut logger = Logger::<257>::default();
360 logger.append_with_args(u64::MAX, &[Argument::Precision(u8::MAX)]);
361 assert!(logger.starts_with("0.00000000000000".as_bytes()));
362 assert!(logger.ends_with("18446744073709551615".as_bytes()));
363
364 logger.clear();
365
366 logger.append_with_args(u32::MAX, &[Argument::Precision(u8::MAX)]);
367 assert!(logger.starts_with("0.00000000000000".as_bytes()));
368 assert!(logger.ends_with("4294967295".as_bytes()));
369
370 logger.clear();
371
372 logger.append_with_args(u16::MAX, &[Argument::Precision(u8::MAX)]);
373 assert!(logger.starts_with("0.00000000000000".as_bytes()));
374 assert!(logger.ends_with("65535".as_bytes()));
375
376 logger.clear();
377
378 logger.append_with_args(u8::MAX, &[Argument::Precision(u8::MAX)]);
379 assert!(logger.starts_with("0.00000000000000".as_bytes()));
380 assert!(logger.ends_with("255".as_bytes()));
381
382 let mut logger = Logger::<258>::default();
384 logger.append_with_args(i64::MIN, &[Argument::Precision(u8::MAX)]);
385 assert!(logger.starts_with("-0.00000000000000".as_bytes()));
386 assert!(logger.ends_with("9223372036854775808".as_bytes()));
387
388 logger.clear();
389
390 logger.append_with_args(i32::MIN, &[Argument::Precision(u8::MAX)]);
391 assert!(logger.starts_with("-0.00000000000000".as_bytes()));
392 assert!(logger.ends_with("2147483648".as_bytes()));
393
394 logger.clear();
395
396 logger.append_with_args(i16::MIN, &[Argument::Precision(u8::MAX)]);
397 assert!(logger.starts_with("-0.00000000000000".as_bytes()));
398 assert!(logger.ends_with("32768".as_bytes()));
399
400 logger.clear();
401
402 logger.append_with_args(i8::MIN, &[Argument::Precision(u8::MAX)]);
403 assert!(logger.starts_with("-0.00000000000000".as_bytes()));
404 assert!(logger.ends_with("128".as_bytes()));
405 }
406
407 #[test]
408 fn test_logger_with_truncate() {
409 let mut logger = Logger::<10>::default();
410
411 logger.append_with_args("0123456789", &[Argument::TruncateEnd(10)]);
412 assert!(&*logger == "0123456789".as_bytes());
413
414 logger.clear();
415
416 logger.append_with_args("0123456789", &[Argument::TruncateStart(10)]);
417 assert!(&*logger == "0123456789".as_bytes());
418
419 logger.clear();
420
421 logger.append_with_args("0123456789", &[Argument::TruncateEnd(9)]);
422 assert!(&*logger == "012345...".as_bytes());
423
424 logger.clear();
425
426 logger.append_with_args("0123456789", &[Argument::TruncateStart(9)]);
427 assert!(&*logger == "...456789".as_bytes());
428
429 let mut logger = Logger::<3>::default();
430
431 logger.append_with_args("0123456789", &[Argument::TruncateEnd(9)]);
432 assert!(&*logger == "..@".as_bytes());
433
434 logger.clear();
435
436 logger.append_with_args("0123456789", &[Argument::TruncateStart(9)]);
437 assert!(&*logger == "..@".as_bytes());
438
439 let mut logger = Logger::<1>::default();
440
441 logger.append_with_args("test", &[Argument::TruncateStart(0)]);
442 assert!(&*logger == "".as_bytes());
443
444 logger.clear();
445
446 logger.append_with_args("test", &[Argument::TruncateStart(1)]);
447 assert!(&*logger == "@".as_bytes());
448
449 let mut logger = Logger::<2>::default();
450
451 logger.append_with_args("test", &[Argument::TruncateStart(2)]);
452 assert!(&*logger == ".@".as_bytes());
453
454 let mut logger = Logger::<3>::default();
455
456 logger.append_with_args("test", &[Argument::TruncateStart(3)]);
457 assert!(&*logger == "..@".as_bytes());
458
459 let mut logger = Logger::<1>::default();
460
461 logger.append_with_args("test", &[Argument::TruncateEnd(0)]);
462 assert!(&*logger == "".as_bytes());
463
464 logger.clear();
465
466 logger.append_with_args("test", &[Argument::TruncateEnd(1)]);
467 assert!(&*logger == "@".as_bytes());
468
469 let mut logger = Logger::<2>::default();
470
471 logger.append_with_args("test", &[Argument::TruncateEnd(2)]);
472 assert!(&*logger == ".@".as_bytes());
473
474 let mut logger = Logger::<3>::default();
475
476 logger.append_with_args("test", &[Argument::TruncateEnd(3)]);
477 assert!(&*logger == "..@".as_bytes());
478 }
479
480 #[test]
481 fn test_logger_with_usize() {
482 let mut logger = Logger::<20>::default();
483
484 logger.append(usize::MIN);
485 assert!(&*logger == "0".as_bytes());
486
487 logger.clear();
488
489 logger.append(usize::MAX);
490
491 #[cfg(target_pointer_width = "32")]
492 {
493 assert!(&*logger == "4294967295".as_bytes());
494 assert_eq!(logger.len(), 10);
495 }
496 #[cfg(target_pointer_width = "64")]
497 {
498 assert!(&*logger == "18446744073709551615".as_bytes());
499 assert_eq!(logger.len(), 20);
500 }
501 }
502
503 #[test]
504 fn test_logger_with_isize() {
505 let mut logger = Logger::<20>::default();
506
507 logger.append(isize::MIN);
508
509 #[cfg(target_pointer_width = "32")]
510 {
511 assert!(&*logger == "-2147483648".as_bytes());
512 assert_eq!(logger.len(), 11);
513 }
514 #[cfg(target_pointer_width = "64")]
515 {
516 assert!(&*logger == "-9223372036854775808".as_bytes());
517 assert_eq!(logger.len(), 20);
518 }
519
520 logger.clear();
521
522 logger.append(isize::MAX);
523
524 #[cfg(target_pointer_width = "32")]
525 {
526 assert!(&*logger == "2147483647".as_bytes());
527 assert_eq!(logger.len(), 10);
528 }
529 #[cfg(target_pointer_width = "64")]
530 {
531 assert!(&*logger == "9223372036854775807".as_bytes());
532 assert_eq!(logger.len(), 19);
533 }
534 }
535
536 #[test]
537 fn test_logger_buffer_size_unsigned() {
538 macro_rules! unsigned_test_case {
540 ( $( ($ty:ident, $max_len:literal) ),+ $(,)? ) => {
541 $(
542 generate_numeric_test_case!($ty::MAX, $max_len, 1,
543 2,
544 3,
545 4,
546 5,
547 6,
548 7,
549 8,
550 9,
551 10,
552 11,
553 12,
554 13,
555 14,
556 15,
557 16,
558 17,
559 18,
560 19,
561 20,
562 50,
563 100,
564 1000);
565 )*
566 };
567 }
568
569 unsigned_test_case!((u8, 3), (u16, 5), (u32, 10), (u64, 20), (usize, 20));
570 #[cfg(not(target_arch = "bpf"))]
571 unsigned_test_case!((u128, 39),);
572 }
573
574 #[test]
575 fn test_logger_buffer_size_signed() {
576 macro_rules! signed_test_case {
578 ( $( ($ty:ident, $max_len:literal) ),+ $(,)? ) => {
579 $(
580 generate_numeric_test_case!($ty::MIN, ($max_len + 1), 1,
581 2,
582 3,
583 4,
584 5,
585 6,
586 7,
587 8,
588 9,
589 10,
590 11,
591 12,
592 13,
593 14,
594 15,
595 16,
596 17,
597 18,
598 19,
599 20,
600 50,
601 100,
602 1000);
603 )*
604 };
605 }
606
607 signed_test_case!((i8, 3), (i16, 5), (i32, 10), (i64, 20), (isize, 20));
608 #[cfg(not(target_arch = "bpf"))]
609 signed_test_case!((i128, 39),);
610 }
611
612 #[test]
613 fn test_logger_buffer_size_str() {
614 macro_rules! str_test_case {
616 ( $( $size:expr ),+ $(,)? ) => {
617 $(
618 generate_str_test_case!(&[b'x'; $size], 1,
619 2,
620 3,
621 4,
622 5,
623 6,
624 7,
625 8,
626 9,
627 10,
628 11,
629 12,
630 13,
631 14,
632 15,
633 16,
634 17,
635 18,
636 19,
637 20,
638 50,
639 100,
640 1000);
641 )*
642 };
643 }
644
645 str_test_case!(1, 5, 10, 50, 100, 1000, 10000);
646 }
647
648 #[test]
649 fn test_logger_bool() {
650 let mut logger = Logger::<5>::default();
651 logger.append(true);
652
653 assert!(&*logger == "true".as_bytes());
654
655 let mut logger = Logger::<5>::default();
656 logger.append(false);
657
658 assert!(&*logger == "false".as_bytes());
659
660 let mut logger = Logger::<3>::default();
661 logger.append(true);
662
663 assert!(&*logger == "tr@".as_bytes());
664
665 let mut logger = Logger::<4>::default();
666 logger.append(false);
667
668 assert!(&*logger == "fal@".as_bytes());
669 }
670}