nstd_sys/io/
stdin.rs

1//! A handle to the standard input stream.
2use crate::{
3    alloc::CBox,
4    core::{
5        alloc::NSTDAllocError,
6        optional::{gen_optional, NSTDOptional},
7        result::NSTDResult,
8        slice::{NSTDSlice, NSTDSliceMut},
9        str::nstd_core_str_from_bytes_unchecked,
10    },
11    io::{NSTDIOError, NSTDIOResult},
12    string::{nstd_string_push_str, NSTDString},
13    vec::NSTDVec,
14};
15use nstdapi::nstdapi;
16use std::io::{Stdin, StdinLock};
17#[cfg(unix)]
18use std::os::unix::io::AsRawFd;
19
20/// A handle to the standard input stream.
21#[nstdapi]
22pub struct NSTDStdin {
23    /// Rust's [Stdin].
24    r#in: CBox<Stdin>,
25}
26gen_optional!(NSTDOptionalStdin, NSTDStdin);
27
28/// Constructs a new handle to the standard input stream.
29///
30/// # Returns
31///
32/// `NSTDOptionalStdin handle` - A handle to the standard input stream on success, or an
33/// uninitialized "none" variant on error.
34#[inline]
35#[nstdapi]
36pub fn nstd_io_stdin() -> NSTDOptionalStdin {
37    CBox::new(std::io::stdin()).map_or(NSTDOptional::None, |r#in| {
38        NSTDOptional::Some(NSTDStdin { r#in })
39    })
40}
41
42/// Reads some data from stdin into a byte slice buffer.
43///
44/// # Note
45///
46/// This function will return an error code of `NSTD_IO_ERROR_INVALID_INPUT` if the buffer's
47/// element size is not 1.
48///
49/// # Parameters:
50///
51/// - `NSTDStdin *handle` - A handle to the standard input stream.
52///
53/// - `NSTDSliceMut *buffer` - The buffer to fill with data from stdin.
54///
55/// # Returns
56///
57/// `NSTDIOResult read` - The number of bytes read from `handle` on success, or the I/O operation
58/// error code on failure.
59///
60/// # Safety
61///
62/// `buffer`'s data must be valid for writes.
63#[inline]
64#[nstdapi]
65pub unsafe fn nstd_io_stdin_read(
66    handle: &mut NSTDStdin,
67    buffer: &mut NSTDSliceMut,
68) -> NSTDIOResult {
69    #[cfg(not(unix))]
70    return crate::io::stdio::read(&mut *handle.r#in, buffer);
71    #[cfg(unix)]
72    return crate::os::unix::io::stdio::read(handle.r#in.lock().as_raw_fd(), buffer).into();
73}
74
75/// Continuously reads data from stdin into a buffer until EOF is reached.
76///
77/// # Note
78///
79/// If extending the buffer fails, an error code of `NSTD_IO_ERROR_OUT_OF_MEMORY` will be returned.
80/// This does not mean there were no bytes read from `handle` in this case.
81///
82/// # Parameters:
83///
84/// - `NSTDStdin *handle` - A handle to the standard input stream.
85///
86/// - `NSTDVec *buffer` - The buffer to be extended with data from stdin.
87///
88/// # Returns
89///
90/// `NSTDIOResult read` - The number of bytes read from `handle` on success, or the I/O operation
91/// error code on failure.
92#[inline]
93#[nstdapi]
94pub fn nstd_io_stdin_read_all(handle: &mut NSTDStdin, buffer: &mut NSTDVec<'_>) -> NSTDIOResult {
95    #[cfg(not(unix))]
96    return crate::io::stdio::read_all(&mut *handle.r#in, buffer);
97    #[cfg(unix)]
98    // SAFETY: `handle` owns the file descriptor.
99    unsafe {
100        crate::os::unix::io::stdio::read_all(handle.r#in.lock().as_raw_fd(), buffer).into()
101    }
102}
103
104/// Continuously reads UTF-8 data from stdin into a string buffer until EOF is reached.
105///
106/// # Note
107///
108/// If extending the buffer fails, an error code of `NSTD_IO_ERROR_OUT_OF_MEMORY` will be returned.
109/// This does not mean there were no bytes read from `handle` in this case.
110///
111/// # Parameters:
112///
113/// - `NSTDStdin *handle` - A handle to the standard input stream.
114///
115/// - `NSTDString *buffer` - The buffer to be extended with data from stdin.
116///
117/// # Returns
118///
119/// `NSTDIOResult read` - The number of bytes read from `handle` on success, or the I/O operation
120/// error code on failure.
121#[inline]
122#[nstdapi]
123pub fn nstd_io_stdin_read_to_string(
124    handle: &mut NSTDStdin,
125    buffer: &mut NSTDString<'_>,
126) -> NSTDIOResult {
127    #[cfg(not(unix))]
128    return crate::io::stdio::read_to_string(&mut *handle.r#in, buffer);
129    #[cfg(unix)]
130    // SAFETY: `handle` owns the file descriptor.
131    unsafe {
132        crate::os::unix::io::stdio::read_to_string(handle.r#in.lock().as_raw_fd(), buffer).into()
133    }
134}
135
136/// Reads enough data from stdin to fill the entirety of `buffer`.
137///
138/// # Note
139///
140/// This function will return an error code of `NSTD_IO_ERROR_INVALID_INPUT` if the buffer's
141/// element size is not 1.
142///
143/// # Parameters:
144///
145/// - `NSTDStdin *handle` - A handle to the standard input stream.
146///
147/// - `NSTDSliceMut *buffer` - The buffer to fill with data from stdin.
148///
149/// # Returns
150///
151/// `NSTDIOError errc` - The I/O operation error code.
152///
153/// # Safety
154///
155/// `buffer` must be valid for writes.
156#[inline]
157#[nstdapi]
158pub unsafe fn nstd_io_stdin_read_exact(
159    handle: &mut NSTDStdin,
160    buffer: &mut NSTDSliceMut,
161) -> NSTDIOError {
162    #[cfg(not(unix))]
163    return crate::io::stdio::read_exact(&mut *handle.r#in, buffer);
164    #[cfg(unix)]
165    return crate::os::unix::io::stdio::read_exact(handle.r#in.lock().as_raw_fd(), buffer).into();
166}
167
168/// Reads a line from stdin and appends it to `buffer`.
169///
170/// # Parameters:
171///
172/// - `NSTDStdin *handle` - A handle to stdin.
173///
174/// - `NSTDString *buffer` - The string buffer to extend with a line from stdin.
175///
176/// # Returns
177///
178/// `NSTDIOResult read` - The number of bytes read from `handle` on success, or the I/O operation
179/// error code on failure.
180#[nstdapi]
181pub fn nstd_io_stdin_read_line(
182    handle: &mut NSTDStdin,
183    buffer: &mut NSTDString<'_>,
184) -> NSTDIOResult {
185    let mut buf = String::new();
186    match handle.r#in.read_line(&mut buf) {
187        Ok(r) => {
188            let bytes = NSTDSlice::from_slice(buf.as_bytes());
189            // SAFETY: `bytes` refers to `buf`'s data, which is still valid UTF-8 here.
190            unsafe {
191                let str = nstd_core_str_from_bytes_unchecked(&bytes);
192                match nstd_string_push_str(buffer, &str) {
193                    NSTDAllocError::NSTD_ALLOC_ERROR_NONE => NSTDResult::Ok(r),
194                    _ => NSTDResult::Err(NSTDIOError::NSTD_IO_ERROR_OUT_OF_MEMORY),
195                }
196            }
197        }
198        Err(err) => NSTDResult::Err(NSTDIOError::from_err(err.kind())),
199    }
200}
201
202/// Frees an instance of `NSTDStdin`.
203///
204/// # Parameters:
205///
206/// - `NSTDStdin handle` - A handle to the standard input stream.
207#[inline]
208#[nstdapi]
209#[allow(
210    unused_variables,
211    clippy::missing_const_for_fn,
212    clippy::needless_pass_by_value
213)]
214pub fn nstd_io_stdin_free(handle: NSTDStdin) {}
215
216/// A locked handle to the standard input stream.
217#[nstdapi]
218pub struct NSTDStdinLock {
219    /// Rust's [StdinLock].
220    r#in: CBox<StdinLock<'static>>,
221}
222gen_optional!(NSTDOptionalStdinLock, NSTDStdinLock);
223
224/// Constructs a new locked handle to the standard input stream.
225///
226/// # Returns
227///
228/// `NSTDOptionalStdinLock handle` - A locked handle to the standard input stream on success, or an
229/// uninitialized "none" variant on error.
230#[inline]
231#[nstdapi]
232pub fn nstd_io_stdin_lock() -> NSTDOptionalStdinLock {
233    CBox::new(std::io::stdin().lock()).map_or(NSTDOptional::None, |r#in| {
234        NSTDOptional::Some(NSTDStdinLock { r#in })
235    })
236}
237
238/// Reads some data from stdin into a byte slice buffer.
239///
240/// # Note
241///
242/// This function will return an error code of `NSTD_IO_ERROR_INVALID_INPUT` if the buffer's
243/// element size is not 1.
244///
245/// # Parameters:
246///
247/// - `NSTDStdinLock *handle` - A locked handle to the standard input stream.
248///
249/// - `NSTDSliceMut *buffer` - The buffer to fill with data from stdin.
250///
251/// # Returns
252///
253/// `NSTDIOResult read` - The number of bytes read from `handle` on success, or the I/O operation
254/// error code on failure.
255///
256/// # Safety
257///
258/// `buffer`'s data must be valid for writes.
259#[inline]
260#[nstdapi]
261pub unsafe fn nstd_io_stdin_lock_read(
262    handle: &mut NSTDStdinLock,
263    buffer: &mut NSTDSliceMut,
264) -> NSTDIOResult {
265    #[cfg(not(unix))]
266    return crate::io::stdio::read(&mut *handle.r#in, buffer);
267    #[cfg(unix)]
268    return crate::os::unix::io::stdio::read(handle.r#in.as_raw_fd(), buffer).into();
269}
270
271/// Continuously reads data from stdin into a buffer until EOF is reached.
272///
273/// # Note
274///
275/// If extending the buffer fails, an error code of `NSTD_IO_ERROR_OUT_OF_MEMORY` will be returned.
276/// This does not mean there were no bytes read from `handle` in this case.
277///
278/// # Parameters:
279///
280/// - `NSTDStdinLock *handle` - A locked handle to the standard input stream.
281///
282/// - `NSTDVec *buffer` - The buffer to be extended with data from stdin.
283///
284/// # Returns
285///
286/// `NSTDIOResult read` - The number of bytes read from `handle` on success, or the I/O operation
287/// error code on failure.
288#[inline]
289#[nstdapi]
290pub fn nstd_io_stdin_lock_read_all(
291    handle: &mut NSTDStdinLock,
292    buffer: &mut NSTDVec<'_>,
293) -> NSTDIOResult {
294    #[cfg(not(unix))]
295    return crate::io::stdio::read_all(&mut *handle.r#in, buffer);
296    #[cfg(unix)]
297    // SAFETY: `handle` owns the file descriptor.
298    unsafe {
299        crate::os::unix::io::stdio::read_all(handle.r#in.as_raw_fd(), buffer).into()
300    }
301}
302
303/// Continuously reads UTF-8 data from stdin into a string buffer until EOF is reached.
304///
305/// # Note
306///
307/// If extending the buffer fails, an error code of `NSTD_IO_ERROR_OUT_OF_MEMORY` will be returned.
308/// This does not mean there were no bytes read from `handle` in this case.
309///
310/// # Parameters:
311///
312/// - `NSTDStdinLock *handle` - A locked handle to the standard input stream.
313///
314/// - `NSTDString *buffer` - The buffer to be extended with data from stdin.
315///
316/// # Returns
317///
318/// `NSTDIOResult read` - The number of bytes read from `handle` on success, or the I/O operation
319/// error code on failure.
320#[inline]
321#[nstdapi]
322pub fn nstd_io_stdin_lock_read_to_string(
323    handle: &mut NSTDStdinLock,
324    buffer: &mut NSTDString<'_>,
325) -> NSTDIOResult {
326    #[cfg(not(unix))]
327    return crate::io::stdio::read_to_string(&mut *handle.r#in, buffer);
328    #[cfg(unix)]
329    // SAFETY: `handle` owns the file descriptor.
330    unsafe {
331        crate::os::unix::io::stdio::read_to_string(handle.r#in.as_raw_fd(), buffer).into()
332    }
333}
334
335/// Reads enough data from stdin to fill the entirety of `buffer`.
336///
337/// # Note
338///
339/// This function will return an error code of `NSTD_IO_ERROR_INVALID_INPUT` if the buffer's
340/// element size is not 1.
341///
342/// # Parameters:
343///
344/// - `NSTDStdinLock *handle` - A locked handle to the standard input stream.
345///
346/// - `NSTDSliceMut *buffer` - The buffer to fill with data from stdin.
347///
348/// # Returns
349///
350/// `NSTDIOError errc` - The I/O operation error code.
351///
352/// # Safety
353///
354/// `buffer` must be valid for writes.
355#[inline]
356#[nstdapi]
357pub unsafe fn nstd_io_stdin_lock_read_exact(
358    handle: &mut NSTDStdinLock,
359    buffer: &mut NSTDSliceMut,
360) -> NSTDIOError {
361    #[cfg(not(unix))]
362    return crate::io::stdio::read_exact(&mut *handle.r#in, buffer);
363    #[cfg(unix)]
364    return crate::os::unix::io::stdio::read_exact(handle.r#in.as_raw_fd(), buffer).into();
365}
366
367/// Frees and unlocks an instance of `NSTDStdinLock`.
368///
369/// # Parameters:
370///
371/// - `NSTDStdinLock handle` - A locked handle to the standard input stream.
372#[inline]
373#[nstdapi]
374#[allow(
375    unused_variables,
376    clippy::missing_const_for_fn,
377    clippy::needless_pass_by_value
378)]
379pub fn nstd_io_stdin_unlock(handle: NSTDStdinLock) {}