use nonblocking_logger::Logger;
use std::io;
use std::io::Write;
use std::path::Path;
use futures::io::AsyncWrite;
fn get_test_dir() -> io::Result<String> {
let test_dir = "target/tests";
if !Path::new(test_dir).exists() {
std::fs::create_dir_all(test_dir)?;
}
Ok(test_dir.to_string())
}
fn get_test_file_path(filename: &str) -> io::Result<String> {
let test_dir = get_test_dir()?;
let timestamp = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default()
.as_nanos();
let safe_filename = filename.replace('/', "_").replace('\\', "_");
Ok(format!("{}/test_{}_{}", test_dir, timestamp, safe_filename))
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("=== AsyncWrite to Write Conversion Example ===");
println!("\n=== Example 1: Custom AsyncWrite implementation ===");
let custom_writer = CustomAsyncWriter::new();
let mut sync_writer = AsyncToSyncWriter::new(custom_writer);
println!("Testing custom AsyncWrite implementation:");
sync_writer.write_all(b"Custom async writer message\n")?;
sync_writer.flush()?;
println!("\n=== Example 2: AsyncToSyncWriter with Vec<u8> ===");
let vec_writer = Vec::<u8>::new();
let mut vec_sync_writer = AsyncToSyncWriter::new(vec_writer);
println!("Testing AsyncToSyncWriter with Vec<u8>:");
vec_sync_writer.write_all(b"Message written to Vec<u8>\n")?;
vec_sync_writer.flush()?;
println!("\n=== Example 3: Using converted AsyncWrite with Logger ===");
let async_writer = Vec::<u8>::new();
let sync_writer = AsyncToSyncWriter::new(async_writer);
let logger = Logger::new().add_target(sync_writer);
println!("Testing converted AsyncWrite with Logger:");
logger.info("This message goes through converted AsyncWrite!")?;
logger.warning("Warning via converted AsyncWrite")?;
logger.error("Error via converted AsyncWrite")?;
println!("\n=== Example 4: Regular Logger with file (for comparison) ===");
let test_file = get_test_file_path("async_example.log")?;
let logger = Logger::new().file(&test_file)?.no_time_prefix();
logger.info("This uses regular Logger with file")?;
logger.warning("Warning via regular Logger file")?;
logger.error("Error via regular Logger file")?;
std::thread::sleep(std::time::Duration::from_millis(100));
std::fs::remove_file(&test_file).ok();
println!("\n=== AsyncWrite to Write Conversion Summary ===");
println!("AsyncToSyncWriter allows you to:");
println!("- Convert any AsyncWrite + Unpin to a sync Write trait");
println!("- Bridge async and sync I/O seamlessly using futures::block_on");
println!("- Create custom AsyncWrite implementations");
println!("- Use async streams with synchronous logging infrastructure");
println!("- Handle network errors gracefully");
Ok(())
}
struct AsyncToSyncWriter<W: AsyncWrite + Unpin> {
writer: W,
}
impl<W: AsyncWrite + Unpin> AsyncToSyncWriter<W> {
fn new(writer: W) -> Self {
Self { writer }
}
}
impl<W: AsyncWrite + Unpin> Write for AsyncToSyncWriter<W> {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
futures::executor::block_on(async {
use futures::io::AsyncWriteExt;
self.writer.write_all(buf).await?;
Ok(buf.len())
})
}
fn flush(&mut self) -> std::io::Result<()> {
futures::executor::block_on(async {
use futures::io::AsyncWriteExt;
self.writer.flush().await
})
}
}
struct CustomAsyncWriter {
buffer: Vec<u8>,
}
impl CustomAsyncWriter {
fn new() -> Self {
Self { buffer: Vec::new() }
}
}
impl futures::io::AsyncWrite for CustomAsyncWriter {
fn poll_write(
mut self: std::pin::Pin<&mut Self>,
_cx: &mut std::task::Context<'_>,
buf: &[u8],
) -> std::task::Poll<std::io::Result<usize>> {
self.buffer.extend_from_slice(buf);
if let Ok(text) = std::str::from_utf8(buf) {
print!("[CUSTOM ASYNC WRITER] {}", text);
}
std::task::Poll::Ready(Ok(buf.len()))
}
fn poll_flush(
self: std::pin::Pin<&mut Self>,
_cx: &mut std::task::Context<'_>,
) -> std::task::Poll<std::io::Result<()>> {
std::task::Poll::Ready(Ok(()))
}
fn poll_close(
self: std::pin::Pin<&mut Self>,
_cx: &mut std::task::Context<'_>,
) -> std::task::Poll<std::io::Result<()>> {
std::task::Poll::Ready(Ok(()))
}
}