use crate::open_input::{open_input, Input};
use crate::{MediaType, Pseudonym};
use basic_text::{ReadText, ReadTextLayered, TextReader, TextSubstr};
use clap::{AmbientAuthority, TryFromOsArg};
use io_streams::StreamReader;
use layered_io::{Bufferable, LayeredReader, ReadLayered, Status};
use std::ffi::OsStr;
use std::fmt::{self, Debug, Formatter};
use std::io::{self, IoSliceMut, Read};
use terminal_io::TerminalReader;
use utf8_io::{ReadStr, ReadStrLayered, Utf8Reader};
pub struct InputTextStream {
name: String,
reader: TextReader<Utf8Reader<LayeredReader<TerminalReader<StreamReader>>>>,
media_type: MediaType,
initial_size: Option<u64>,
}
impl InputTextStream {
pub fn media_type(&self) -> &MediaType {
&self.media_type
}
pub fn initial_size(&self) -> Option<u64> {
self.initial_size
}
pub fn pseudonym(&self) -> Pseudonym {
Pseudonym::new(self.name.clone())
}
fn from_input(input: Input) -> Self {
let reader = TerminalReader::with_handle(input.reader);
let reader = TextReader::new(reader);
let media_type = input.media_type.union(MediaType::text());
Self {
name: input.name,
reader,
media_type,
initial_size: input.initial_size,
}
}
}
#[doc(hidden)]
impl TryFromOsArg for InputTextStream {
type Error = anyhow::Error;
#[inline]
fn try_from_os_str_arg(
os: &OsStr,
ambient_authority: AmbientAuthority,
) -> anyhow::Result<Self> {
open_input(os, ambient_authority).map(Self::from_input)
}
}
impl ReadLayered for InputTextStream {
#[inline]
fn read_with_status(&mut self, buf: &mut [u8]) -> io::Result<(usize, Status)> {
self.reader.read_with_status(buf)
}
#[inline]
fn read_vectored_with_status(
&mut self,
bufs: &mut [IoSliceMut<'_>],
) -> io::Result<(usize, Status)> {
self.reader.read_vectored_with_status(bufs)
}
}
impl Read for InputTextStream {
#[inline]
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.reader.read(buf)
}
#[inline]
fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
self.reader.read_vectored(bufs)
}
#[cfg(can_vector)]
#[inline]
fn is_read_vectored(&self) -> bool {
self.reader.is_read_vectored()
}
#[inline]
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
self.reader.read_to_end(buf)
}
#[inline]
fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
self.reader.read_to_string(buf)
}
#[inline]
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
self.reader.read_exact(buf)
}
}
impl Bufferable for InputTextStream {
#[inline]
fn abandon(&mut self) {
self.reader.abandon()
}
}
impl ReadStr for InputTextStream {
#[inline]
fn read_str(&mut self, buf: &mut str) -> io::Result<usize> {
self.reader.read_str(buf)
}
}
impl ReadStrLayered for InputTextStream {
#[inline]
fn read_str_with_status(&mut self, buf: &mut str) -> io::Result<(usize, Status)> {
self.reader.read_str_with_status(buf)
}
}
impl ReadText for InputTextStream {
#[inline]
fn read_text_substr(&mut self, buf: &mut TextSubstr) -> io::Result<usize> {
self.reader.read_text_substr(buf)
}
#[inline]
fn read_exact_text_substr(&mut self, buf: &mut TextSubstr) -> io::Result<()> {
self.reader.read_exact_text_substr(buf)
}
}
impl ReadTextLayered for InputTextStream {
#[inline]
fn read_text_substr_with_status(
&mut self,
buf: &mut TextSubstr,
) -> io::Result<(usize, Status)> {
self.reader.read_text_substr_with_status(buf)
}
#[inline]
fn read_exact_text_substr_using_status(&mut self, buf: &mut TextSubstr) -> io::Result<Status> {
self.reader.read_exact_text_substr_using_status(buf)
}
}
impl Debug for InputTextStream {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let mut b = f.debug_struct("InputTextStream");
b.field("media_type", &self.media_type);
b.field("initial_size", &self.initial_size);
b.finish()
}
}
#[test]
fn data_url_plain() {
let mut s = String::new();
InputTextStream::try_from_os_str_arg(
"data:,Hello%2C%20World!".as_ref(),
clap::ambient_authority(),
)
.unwrap()
.read_to_string(&mut s)
.unwrap();
assert_eq!(s, "Hello, World!\n");
}
#[test]
fn data_url_base64() {
let mut s = String::new();
InputTextStream::try_from_os_str_arg(
"data:text/plain;base64,SGVsbG8sIFdvcmxkIQ==".as_ref(),
clap::ambient_authority(),
)
.unwrap()
.read_to_string(&mut s)
.unwrap();
assert_eq!(s, "Hello, World!\n");
}