fslock/
fmt.rs

1//! This module implements formatting functions for writing into lock files.
2
3use crate::sys;
4use core::{
5    fmt::{self, Write},
6    mem,
7};
8
9/// I/O buffer size, chosen targeting possible PID's digits (I belive 11 would
10/// be enough tho).
11const BUF_SIZE: usize = 16;
12
13/// A fmt Writer that writes data into the given open file.
14#[derive(Debug, Clone, Copy)]
15pub struct Writer(
16    /// The open file to which data will be written.
17    pub sys::FileDesc,
18);
19
20impl Writer {
21    /// Writes formatting arguments into the file.
22    pub fn write_fmt(
23        &self,
24        arguments: fmt::Arguments,
25    ) -> Result<(), sys::Error> {
26        let mut adapter = Adapter::new(self.0);
27        let _ = adapter.write_fmt(arguments);
28        adapter.finish()
29    }
30}
31
32/// Fmt <-> IO adapter.
33///
34/// Buffer is flushed on drop.
35#[derive(Debug)]
36struct Adapter {
37    /// File being written to.
38    desc: sys::FileDesc,
39    /// Temporary buffer of bytes being written.
40    buffer: [u8; BUF_SIZE],
41    /// Cursor tracking where new bytes should be written at the buffer.
42    cursor: usize,
43    /// Partial result for writes.
44    result: Result<(), sys::Error>,
45}
46
47impl Adapter {
48    /// Creates a zeroed adapter from an open file.
49    fn new(desc: sys::FileDesc) -> Self {
50        Self { desc, buffer: [0; BUF_SIZE], cursor: 0, result: Ok(()) }
51    }
52
53    /// Flushes the buffer into the open file.
54    fn flush(&mut self) -> Result<(), sys::Error> {
55        sys::write(self.desc, &self.buffer[.. self.cursor])?;
56        self.buffer = [0; BUF_SIZE];
57        self.cursor = 0;
58        Ok(())
59    }
60
61    /// Finishes the adapter, returning the I/O Result
62    fn finish(mut self) -> Result<(), sys::Error> {
63        mem::replace(&mut self.result, Ok(()))
64    }
65}
66
67impl Write for Adapter {
68    fn write_str(&mut self, data: &str) -> fmt::Result {
69        let mut bytes = data.as_bytes();
70
71        while bytes.len() > 0 && self.result.is_ok() {
72            let start = self.cursor;
73            let size = (BUF_SIZE - self.cursor).min(bytes.len());
74            let end = start + size;
75
76            self.buffer[start .. end].copy_from_slice(&bytes[.. size]);
77            self.cursor = end;
78            bytes = &bytes[size ..];
79
80            if bytes.len() > 0 {
81                self.result = self.flush();
82            }
83        }
84
85        match self.result {
86            Ok(_) => Ok(()),
87            Err(_) => Err(fmt::Error),
88        }
89    }
90}
91
92impl Drop for Adapter {
93    fn drop(&mut self) {
94        let _ = self.flush();
95        let _ = sys::fsync(self.desc);
96    }
97}