1#[cfg(feature = "os")]
6use crate::process::{ChildPipe, ChildProcess};
7use crate::{
8 IntRange, PipelineData, ShellError, Signals, Span, Type, Value,
9 shell_error::{bridge::ShellErrorBridge, io::IoError},
10};
11use nu_utils::SplitRead as SplitReadInner;
12use serde::{Deserialize, Serialize};
13use std::ops::Bound;
14#[cfg(unix)]
15use std::os::fd::OwnedFd;
16#[cfg(windows)]
17use std::os::windows::io::OwnedHandle;
18use std::{
19 fmt::Debug,
20 fs::File,
21 io::{self, BufRead, BufReader, Cursor, ErrorKind, Read, Write},
22 process::Stdio,
23};
24
25pub enum ByteStreamSource {
32 Read(Box<dyn Read + Send + 'static>),
33 File(File),
34 #[cfg(feature = "os")]
35 Child(Box<ChildProcess>),
36}
37
38impl ByteStreamSource {
39 fn reader(self) -> Option<SourceReader> {
40 match self {
41 ByteStreamSource::Read(read) => Some(SourceReader::Read(read)),
42 ByteStreamSource::File(file) => Some(SourceReader::File(file)),
43 #[cfg(feature = "os")]
44 ByteStreamSource::Child(mut child) => child.stdout.take().map(|stdout| match stdout {
45 ChildPipe::Pipe(pipe) => SourceReader::File(convert_file(pipe)),
46 ChildPipe::Tee(tee) => SourceReader::Read(tee),
47 }),
48 }
49 }
50
51 #[cfg(feature = "os")]
53 pub fn is_external(&self) -> bool {
54 matches!(self, ByteStreamSource::Child(..))
55 }
56
57 #[cfg(not(feature = "os"))]
58 pub fn is_external(&self) -> bool {
59 false
61 }
62}
63
64impl Debug for ByteStreamSource {
65 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
66 match self {
67 ByteStreamSource::Read(_) => f.debug_tuple("Read").field(&"..").finish(),
68 ByteStreamSource::File(file) => f.debug_tuple("File").field(file).finish(),
69 #[cfg(feature = "os")]
70 ByteStreamSource::Child(child) => f.debug_tuple("Child").field(child).finish(),
71 }
72 }
73}
74
75enum SourceReader {
76 Read(Box<dyn Read + Send + 'static>),
77 File(File),
78}
79
80impl Read for SourceReader {
81 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
82 match self {
83 SourceReader::Read(reader) => reader.read(buf),
84 SourceReader::File(file) => file.read(buf),
85 }
86 }
87}
88
89impl Debug for SourceReader {
90 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
91 match self {
92 SourceReader::Read(_) => f.debug_tuple("Read").field(&"..").finish(),
93 SourceReader::File(file) => f.debug_tuple("File").field(file).finish(),
94 }
95 }
96}
97
98#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
100pub enum ByteStreamType {
101 Binary,
104 String,
110 #[default]
113 Unknown,
114}
115
116impl ByteStreamType {
117 pub fn describe(self) -> &'static str {
120 match self {
121 ByteStreamType::Binary => "binary (stream)",
122 ByteStreamType::String => "string (stream)",
123 ByteStreamType::Unknown => "byte stream",
124 }
125 }
126
127 pub fn is_binary_coercible(self) -> bool {
129 matches!(self, ByteStreamType::Binary | ByteStreamType::Unknown)
130 }
131
132 pub fn is_string_coercible(self) -> bool {
134 matches!(self, ByteStreamType::String | ByteStreamType::Unknown)
135 }
136}
137
138impl From<ByteStreamType> for Type {
139 fn from(value: ByteStreamType) -> Self {
140 match value {
141 ByteStreamType::Binary => Type::Binary,
142 ByteStreamType::String => Type::String,
143 ByteStreamType::Unknown => Type::Any,
144 }
145 }
146}
147
148#[derive(Debug)]
191pub struct ByteStream {
192 stream: ByteStreamSource,
193 span: Span,
194 signals: Signals,
195 type_: ByteStreamType,
196 known_size: Option<u64>,
197 caller_spans: Vec<Span>,
198}
199
200impl ByteStream {
201 pub fn new(
203 stream: ByteStreamSource,
204 span: Span,
205 signals: Signals,
206 type_: ByteStreamType,
207 ) -> Self {
208 Self {
209 stream,
210 span,
211 signals,
212 type_,
213 known_size: None,
214 caller_spans: vec![],
215 }
216 }
217
218 pub fn push_caller_span(&mut self, span: Span) {
220 if span != self.span {
221 self.caller_spans.push(span)
222 }
223 }
224
225 pub fn get_caller_spans(&self) -> &Vec<Span> {
227 &self.caller_spans
228 }
229
230 pub fn read(
232 reader: impl Read + Send + 'static,
233 span: Span,
234 signals: Signals,
235 type_: ByteStreamType,
236 ) -> Self {
237 Self::new(
238 ByteStreamSource::Read(Box::new(reader)),
239 span,
240 signals,
241 type_,
242 )
243 }
244
245 pub fn skip(self, span: Span, n: u64) -> Result<Self, ShellError> {
246 let known_size = self.known_size.map(|len| len.saturating_sub(n));
247 if let Some(mut reader) = self.reader() {
248 io::copy(&mut (&mut reader).take(n), &mut io::sink())
250 .map_err(|err| IoError::new(err, span, None))?;
251 Ok(
252 ByteStream::read(reader, span, Signals::empty(), ByteStreamType::Binary)
253 .with_known_size(known_size),
254 )
255 } else {
256 Err(ShellError::TypeMismatch {
257 err_message: "expected readable stream".into(),
258 span,
259 })
260 }
261 }
262
263 pub fn take(self, span: Span, n: u64) -> Result<Self, ShellError> {
264 let known_size = self.known_size.map(|s| s.min(n));
265 if let Some(reader) = self.reader() {
266 Ok(ByteStream::read(
267 reader.take(n),
268 span,
269 Signals::empty(),
270 ByteStreamType::Binary,
271 )
272 .with_known_size(known_size))
273 } else {
274 Err(ShellError::TypeMismatch {
275 err_message: "expected readable stream".into(),
276 span,
277 })
278 }
279 }
280
281 pub fn slice(
282 self,
283 val_span: Span,
284 call_span: Span,
285 range: IntRange,
286 ) -> Result<Self, ShellError> {
287 if let Some(len) = self.known_size {
288 let start = range.absolute_start(len);
289 let stream = self.skip(val_span, start);
290
291 match range.absolute_end(len) {
292 Bound::Unbounded => stream,
293 Bound::Included(end) | Bound::Excluded(end) if end < start => {
294 stream.and_then(|s| s.take(val_span, 0))
295 }
296 Bound::Included(end) => {
297 let distance = end - start + 1;
298 stream.and_then(|s| s.take(val_span, distance.min(len)))
299 }
300 Bound::Excluded(end) => {
301 let distance = end - start;
302 stream.and_then(|s| s.take(val_span, distance.min(len)))
303 }
304 }
305 } else if range.is_relative() {
306 Err(ShellError::RelativeRangeOnInfiniteStream { span: call_span })
307 } else {
308 let start = range.start() as u64;
309 let stream = self.skip(val_span, start);
310
311 match range.distance() {
312 Bound::Unbounded => stream,
313 Bound::Included(distance) => stream.and_then(|s| s.take(val_span, distance + 1)),
314 Bound::Excluded(distance) => stream.and_then(|s| s.take(val_span, distance)),
315 }
316 }
317 }
318
319 pub fn read_string(string: String, span: Span, signals: Signals) -> Self {
321 let len = string.len();
322 ByteStream::read(
323 Cursor::new(string.into_bytes()),
324 span,
325 signals,
326 ByteStreamType::String,
327 )
328 .with_known_size(Some(len as u64))
329 }
330
331 pub fn read_binary<T>(bytes: T, span: Span, signals: Signals) -> Self
333 where
334 T: AsRef<[u8]> + Send + 'static,
335 {
336 let len = bytes.as_ref().len();
337 ByteStream::read(Cursor::new(bytes), span, signals, ByteStreamType::Binary)
338 .with_known_size(Some(len as u64))
339 }
340
341 pub fn file(file: File, span: Span, signals: Signals) -> Self {
346 Self::new(
347 ByteStreamSource::File(file),
348 span,
349 signals,
350 ByteStreamType::Unknown,
351 )
352 }
353
354 #[cfg(feature = "os")]
359 pub fn child(child: ChildProcess, span: Span) -> Self {
360 Self::new(
361 ByteStreamSource::Child(Box::new(child)),
362 span,
363 Signals::empty(),
364 ByteStreamType::Unknown,
365 )
366 }
367
368 #[cfg(feature = "os")]
373 pub fn stdin(span: Span) -> Result<Self, ShellError> {
374 let stdin = os_pipe::dup_stdin().map_err(|err| IoError::new(err, span, None))?;
375 let source = ByteStreamSource::File(convert_file(stdin));
376 Ok(Self::new(
377 source,
378 span,
379 Signals::empty(),
380 ByteStreamType::Unknown,
381 ))
382 }
383
384 #[cfg(not(feature = "os"))]
385 pub fn stdin(span: Span) -> Result<Self, ShellError> {
386 Err(ShellError::DisabledOsSupport {
387 msg: "Stdin is not supported".to_string(),
388 span,
389 })
390 }
391
392 pub fn from_fn(
395 span: Span,
396 signals: Signals,
397 type_: ByteStreamType,
398 generator: impl FnMut(&mut Vec<u8>) -> Result<bool, ShellError> + Send + 'static,
399 ) -> Self {
400 Self::read(
401 ReadGenerator {
402 buffer: Cursor::new(Vec::new()),
403 generator,
404 },
405 span,
406 signals,
407 type_,
408 )
409 }
410
411 pub fn with_type(mut self, type_: ByteStreamType) -> Self {
412 self.type_ = type_;
413 self
414 }
415
416 pub fn from_iter<I>(iter: I, span: Span, signals: Signals, type_: ByteStreamType) -> Self
420 where
421 I: IntoIterator,
422 I::IntoIter: Send + 'static,
423 I::Item: AsRef<[u8]> + Default + Send + 'static,
424 {
425 let iter = iter.into_iter();
426 let cursor = Some(Cursor::new(I::Item::default()));
427 Self::read(ReadIterator { iter, cursor }, span, signals, type_)
428 }
429
430 pub fn from_result_iter<I, T>(
434 iter: I,
435 span: Span,
436 signals: Signals,
437 type_: ByteStreamType,
438 ) -> Self
439 where
440 I: IntoIterator<Item = Result<T, ShellError>>,
441 I::IntoIter: Send + 'static,
442 T: AsRef<[u8]> + Default + Send + 'static,
443 {
444 let iter = iter.into_iter();
445 let cursor = Some(Cursor::new(T::default()));
446 Self::read(ReadResultIterator { iter, cursor }, span, signals, type_)
447 }
448
449 pub fn with_known_size(mut self, size: Option<u64>) -> Self {
451 self.known_size = size;
452 self
453 }
454
455 pub fn source(&self) -> &ByteStreamSource {
457 &self.stream
458 }
459
460 pub fn source_mut(&mut self) -> &mut ByteStreamSource {
462 &mut self.stream
463 }
464
465 pub fn span(&self) -> Span {
467 self.span
468 }
469
470 pub fn with_span(mut self, span: Span) -> Self {
472 self.span = span;
473 self
474 }
475
476 pub fn signals(&self) -> &Signals {
479 &self.signals
480 }
481
482 pub fn type_(&self) -> ByteStreamType {
483 self.type_
484 }
485
486 pub fn known_size(&self) -> Option<u64> {
488 self.known_size
489 }
490
491 pub fn reader(self) -> Option<Reader> {
498 let reader = self.stream.reader()?;
499 Some(Reader {
500 reader: BufReader::new(reader),
501 span: self.span,
502 signals: self.signals,
503 })
504 }
505
506 pub fn lines(self) -> Option<Lines> {
514 let reader = self.stream.reader()?;
515 Some(Lines {
516 reader: BufReader::new(reader),
517 span: self.span,
518 signals: self.signals,
519 strict: false,
520 })
521 }
522
523 pub fn split(self, delimiter: Vec<u8>) -> Option<SplitRead> {
531 let reader = self.stream.reader()?;
532 Some(SplitRead::new(reader, delimiter, self.span, self.signals))
533 }
534
535 pub fn chunks(self) -> Option<Chunks> {
551 let reader = self.stream.reader()?;
552 Some(Chunks::new(reader, self.span, self.signals, self.type_))
553 }
554
555 pub fn into_source(self) -> ByteStreamSource {
557 self.stream
558 }
559
560 pub fn into_stdio(mut self) -> Result<Stdio, Self> {
568 match self.stream {
569 ByteStreamSource::Read(..) => Err(self),
570 ByteStreamSource::File(file) => Ok(file.into()),
571 #[cfg(feature = "os")]
572 ByteStreamSource::Child(child) => {
573 if let ChildProcess {
574 stdout: Some(ChildPipe::Pipe(stdout)),
575 stderr,
576 ..
577 } = *child
578 {
579 debug_assert!(stderr.is_none(), "stderr should not exist");
580 Ok(stdout.into())
581 } else {
582 self.stream = ByteStreamSource::Child(child);
583 Err(self)
584 }
585 }
586 }
587 }
588
589 #[cfg(feature = "os")]
594 pub fn into_child(self) -> Result<ChildProcess, Self> {
595 if let ByteStreamSource::Child(child) = self.stream {
596 Ok(*child)
597 } else {
598 Err(self)
599 }
600 }
601
602 pub fn into_bytes(self) -> Result<Vec<u8>, ShellError> {
606 let span = self.span;
607 let signals = self.signals;
608 let from_io_error = IoError::factory(span, None);
609 match self.stream {
610 ByteStreamSource::Read(mut read) => {
611 let mut buf = Vec::new();
612 let mut chunk = [0; DEFAULT_BUF_SIZE];
613 loop {
614 signals.check(&span)?;
615 match read.read(&mut chunk) {
616 Ok(0) => break,
617 Ok(n) => buf.extend_from_slice(&chunk[..n]),
618 Err(e) if e.kind() == ErrorKind::Interrupted => continue,
619 Err(e) => match ShellErrorBridge::try_from(e) {
620 Ok(ShellErrorBridge(e)) => return Err(e),
621 Err(e) => return Err(ShellError::Io(from_io_error(e))),
622 },
623 }
624 }
625 Ok(buf)
626 }
627 ByteStreamSource::File(mut file) => {
628 let mut buf = Vec::new();
629 let mut chunk = [0; DEFAULT_BUF_SIZE];
630 loop {
631 signals.check(&span)?;
632 match file.read(&mut chunk) {
633 Ok(0) => break,
634 Ok(n) => buf.extend_from_slice(&chunk[..n]),
635 Err(e) if e.kind() == ErrorKind::Interrupted => continue,
636 Err(e) => return Err(ShellError::Io(from_io_error(e))),
637 }
638 }
639 Ok(buf)
640 }
641 #[cfg(feature = "os")]
642 ByteStreamSource::Child(child) => child.into_bytes(),
643 }
644 }
645
646 pub fn into_string(self) -> Result<String, ShellError> {
655 let span = self.span;
656 if self.type_.is_string_coercible() {
657 let trim = self.stream.is_external();
658 let bytes = self.into_bytes()?;
659 let mut string = String::from_utf8(bytes).map_err(|err| ShellError::NonUtf8Custom {
660 span,
661 msg: err.to_string(),
662 })?;
663 if trim {
664 trim_end_newline(&mut string);
665 }
666 Ok(string)
667 } else {
668 Err(ShellError::TypeMismatch {
669 err_message: "expected string, but got binary".into(),
670 span,
671 })
672 }
673 }
674
675 pub fn into_value(self) -> Result<Value, ShellError> {
688 let span = self.span;
689 let trim = self.stream.is_external();
690 let value = match self.type_ {
691 ByteStreamType::Binary => Value::binary(self.into_bytes()?, span),
693 ByteStreamType::String => Value::string(self.into_string()?, span),
695 ByteStreamType::Unknown => {
697 value_from_bytes(self.into_bytes()?, span, ByteStreamType::Unknown, trim)
698 }
699 };
700 Ok(value)
701 }
702
703 pub fn drain(self) -> Result<(), ShellError> {
705 match self.stream {
706 ByteStreamSource::Read(read) => {
707 copy_with_signals(read, io::sink(), self.span, &self.signals)?;
708 Ok(())
709 }
710 ByteStreamSource::File(_) => Ok(()),
711 #[cfg(feature = "os")]
712 ByteStreamSource::Child(child) => child.wait(),
713 }
714 }
715
716 pub fn print(self, to_stderr: bool) -> Result<(), ShellError> {
718 if to_stderr {
719 self.write_to(&mut io::stderr())
720 } else {
721 self.write_to(&mut io::stdout())
722 }
723 }
724
725 pub fn write_to(self, dest: impl Write) -> Result<(), ShellError> {
727 let span = self.span;
728 let signals = &self.signals;
729 match self.stream {
730 ByteStreamSource::Read(read) => {
731 copy_with_signals(read, dest, span, signals)?;
732 }
733 ByteStreamSource::File(file) => {
734 copy_with_signals(file, dest, span, signals)?;
735 }
736 #[cfg(feature = "os")]
737 ByteStreamSource::Child(mut child) => {
738 debug_assert!(child.stderr.is_none(), "stderr should not exist");
742
743 if let Some(stdout) = child.stdout.take() {
744 match stdout {
745 ChildPipe::Pipe(pipe) => {
746 copy_with_signals(pipe, dest, span, signals)?;
747 }
748 ChildPipe::Tee(tee) => {
749 copy_with_signals(tee, dest, span, signals)?;
750 }
751 }
752 }
753 child.wait()?;
754 }
755 }
756 Ok(())
757 }
758}
759
760impl From<ByteStream> for PipelineData {
761 fn from(stream: ByteStream) -> Self {
762 Self::byte_stream(stream, None)
763 }
764}
765
766struct ReadIterator<I>
767where
768 I: Iterator,
769 I::Item: AsRef<[u8]>,
770{
771 iter: I,
772 cursor: Option<Cursor<I::Item>>,
773}
774
775impl<I> Read for ReadIterator<I>
776where
777 I: Iterator,
778 I::Item: AsRef<[u8]>,
779{
780 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
781 while let Some(cursor) = self.cursor.as_mut() {
782 let read = cursor.read(buf)?;
783 if read == 0 {
784 self.cursor = self.iter.next().map(Cursor::new);
785 } else {
786 return Ok(read);
787 }
788 }
789 Ok(0)
790 }
791}
792
793struct ReadResultIterator<I, T>
794where
795 I: Iterator<Item = Result<T, ShellError>>,
796 T: AsRef<[u8]>,
797{
798 iter: I,
799 cursor: Option<Cursor<T>>,
800}
801
802impl<I, T> Read for ReadResultIterator<I, T>
803where
804 I: Iterator<Item = Result<T, ShellError>>,
805 T: AsRef<[u8]>,
806{
807 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
808 while let Some(cursor) = self.cursor.as_mut() {
809 let read = cursor.read(buf)?;
810 if read == 0 {
811 self.cursor = self
812 .iter
813 .next()
814 .transpose()
815 .map_err(ShellErrorBridge)?
816 .map(Cursor::new);
817 } else {
818 return Ok(read);
819 }
820 }
821 Ok(0)
822 }
823}
824
825pub struct Reader {
826 reader: BufReader<SourceReader>,
827 span: Span,
828 signals: Signals,
829}
830
831impl Reader {
832 pub fn span(&self) -> Span {
833 self.span
834 }
835}
836
837impl Read for Reader {
838 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
839 self.signals.check(&self.span).map_err(ShellErrorBridge)?;
840 self.reader.read(buf)
841 }
842}
843
844impl BufRead for Reader {
845 fn fill_buf(&mut self) -> io::Result<&[u8]> {
846 self.reader.fill_buf()
847 }
848
849 fn consume(&mut self, amt: usize) {
850 self.reader.consume(amt)
851 }
852}
853
854pub struct Lines {
855 reader: BufReader<SourceReader>,
856 span: Span,
857 signals: Signals,
858 strict: bool,
867}
868
869impl Lines {
870 pub fn span(&self) -> Span {
871 self.span
872 }
873
874 pub fn strict(mut self, strict: bool) -> Self {
880 self.strict = strict;
881 self
882 }
883}
884
885impl Iterator for Lines {
886 type Item = Result<String, ShellError>;
887
888 fn next(&mut self) -> Option<Self::Item> {
889 if self.signals.interrupted() {
890 None
891 } else {
892 let mut buf = Vec::new();
893 match self.reader.read_until(b'\n', &mut buf) {
894 Ok(0) => None,
895 Ok(_) => {
896 let mut string = if self.strict {
897 match String::from_utf8(buf) {
898 Ok(s) => s,
899 Err(_) => return Some(Err(ShellError::NonUtf8 { span: self.span })),
900 }
901 } else {
902 String::from_utf8_lossy(&buf).into_owned()
903 };
904 trim_end_newline(&mut string);
905 Some(Ok(string))
906 }
907 Err(err) => Some(Err(IoError::new(err, self.span, None).into())),
908 }
909 }
910 }
911}
912
913pub struct SplitRead {
914 internal: SplitReadInner<BufReader<SourceReader>>,
915 span: Span,
916 signals: Signals,
917}
918
919impl SplitRead {
920 fn new(
921 reader: SourceReader,
922 delimiter: impl AsRef<[u8]>,
923 span: Span,
924 signals: Signals,
925 ) -> Self {
926 Self {
927 internal: SplitReadInner::new(BufReader::new(reader), delimiter),
928 span,
929 signals,
930 }
931 }
932
933 pub fn span(&self) -> Span {
934 self.span
935 }
936}
937
938impl Iterator for SplitRead {
939 type Item = Result<Vec<u8>, ShellError>;
940
941 fn next(&mut self) -> Option<Self::Item> {
942 if self.signals.interrupted() {
943 return None;
944 }
945 self.internal.next().map(|r| {
946 r.map_err(|err| {
947 ShellError::Io(IoError::new_internal(
948 err,
949 "Could not get next value for SplitRead",
950 ))
951 })
952 })
953 }
954}
955
956pub struct Chunks {
962 reader: BufReader<SourceReader>,
963 pos: u64,
964 error: bool,
965 span: Span,
966 signals: Signals,
967 type_: ByteStreamType,
968}
969
970impl Chunks {
971 fn new(reader: SourceReader, span: Span, signals: Signals, type_: ByteStreamType) -> Self {
972 Self {
973 reader: BufReader::new(reader),
974 pos: 0,
975 error: false,
976 span,
977 signals,
978 type_,
979 }
980 }
981
982 pub fn span(&self) -> Span {
983 self.span
984 }
985
986 fn next_string(&mut self) -> Result<Option<String>, (Vec<u8>, ShellError)> {
987 let from_io_error = |err: std::io::Error| match ShellErrorBridge::try_from(err) {
988 Ok(err) => err.0,
989 Err(err) => IoError::new(err, self.span, None).into(),
990 };
991
992 let buf = self
994 .reader
995 .fill_buf()
996 .map_err(from_io_error)
997 .map_err(|err| (vec![], err))?;
998
999 if buf.is_empty() {
1001 return Ok(None);
1002 }
1003
1004 let mut buf = buf.to_vec();
1005 let mut consumed = 0;
1006
1007 if buf.len() < 4 {
1009 consumed += buf.len();
1010 self.reader.consume(buf.len());
1011 match self.reader.fill_buf() {
1012 Ok(more_bytes) => buf.extend_from_slice(more_bytes),
1013 Err(err) => return Err((buf, from_io_error(err))),
1014 }
1015 }
1016
1017 match String::from_utf8(buf) {
1019 Ok(string) => {
1020 self.reader.consume(string.len() - consumed);
1021 self.pos += string.len() as u64;
1022 Ok(Some(string))
1023 }
1024 Err(err) if err.utf8_error().error_len().is_none() => {
1025 let valid_up_to = err.utf8_error().valid_up_to();
1028 if valid_up_to > consumed {
1029 self.reader.consume(valid_up_to - consumed);
1030 }
1031 let mut buf = err.into_bytes();
1032 buf.truncate(valid_up_to);
1033 buf.shrink_to_fit();
1034 let string = String::from_utf8(buf)
1035 .expect("failed to parse utf-8 even after correcting error");
1036 self.pos += string.len() as u64;
1037 Ok(Some(string))
1038 }
1039 Err(err) => {
1040 let shell_error = ShellError::NonUtf8Custom {
1042 msg: format!("invalid utf-8 sequence starting at index {}", self.pos),
1043 span: self.span,
1044 };
1045 let buf = err.into_bytes();
1046 if buf.len() > consumed {
1049 self.reader.consume(buf.len() - consumed);
1050 }
1051 self.pos += buf.len() as u64;
1052 Err((buf, shell_error))
1053 }
1054 }
1055 }
1056}
1057
1058impl Iterator for Chunks {
1059 type Item = Result<Value, ShellError>;
1060
1061 fn next(&mut self) -> Option<Self::Item> {
1062 if self.error || self.signals.interrupted() {
1063 None
1064 } else {
1065 match self.type_ {
1066 ByteStreamType::Binary => {
1068 let buf = match self.reader.fill_buf() {
1069 Ok(buf) => buf,
1070 Err(err) => {
1071 self.error = true;
1072 return Some(Err(ShellError::Io(IoError::new(err, self.span, None))));
1073 }
1074 };
1075 if !buf.is_empty() {
1076 let len = buf.len();
1077 let value = Value::binary(buf, self.span);
1078 self.reader.consume(len);
1079 self.pos += len as u64;
1080 Some(Ok(value))
1081 } else {
1082 None
1083 }
1084 }
1085 ByteStreamType::String => match self.next_string().transpose()? {
1087 Ok(string) => Some(Ok(Value::string(string, self.span))),
1088 Err((_, err)) => {
1089 self.error = true;
1090 Some(Err(err))
1091 }
1092 },
1093 ByteStreamType::Unknown => {
1096 match self.next_string().transpose()? {
1097 Ok(string) => Some(Ok(Value::string(string, self.span))),
1098 Err((buf, _)) if !buf.is_empty() => {
1099 self.type_ = ByteStreamType::Binary;
1101 Some(Ok(Value::binary(buf, self.span)))
1102 }
1103 Err((_, err)) => {
1104 self.error = true;
1105 Some(Err(err))
1106 }
1107 }
1108 }
1109 }
1110 }
1111 }
1112}
1113
1114fn trim_end_newline(string: &mut String) {
1115 if string.ends_with('\n') {
1116 string.pop();
1117 if string.ends_with('\r') {
1118 string.pop();
1119 }
1120 }
1121}
1122
1123pub fn value_from_bytes(
1137 bytes: Vec<u8>,
1138 span: Span,
1139 type_: ByteStreamType,
1140 trim_trailing_newline: bool,
1141) -> Value {
1142 if matches!(type_, ByteStreamType::Binary) {
1143 return Value::binary(bytes, span);
1144 }
1145
1146 match String::from_utf8(bytes) {
1147 Ok(mut s) => {
1148 if trim_trailing_newline {
1149 trim_end_newline(&mut s);
1150 }
1151 Value::string(s, span)
1152 }
1153 Err(err) => {
1154 let valid_up_to = err.utf8_error().valid_up_to();
1155 let incomplete_at_end = err.utf8_error().error_len().is_none();
1157 let bytes = err.into_bytes();
1158 if incomplete_at_end && valid_up_to > 0 {
1159 let mut s = String::from_utf8(bytes[..valid_up_to].to_vec())
1161 .expect("valid_up_to marks a valid UTF-8 prefix");
1162 if trim_trailing_newline {
1163 trim_end_newline(&mut s);
1164 }
1165 Value::string(s, span)
1166 } else {
1167 Value::binary(bytes, span)
1168 }
1169 }
1170 }
1171}
1172
1173#[cfg(unix)]
1174pub(crate) fn convert_file<T: From<OwnedFd>>(file: impl Into<OwnedFd>) -> T {
1175 file.into().into()
1176}
1177
1178#[cfg(windows)]
1179pub(crate) fn convert_file<T: From<OwnedHandle>>(file: impl Into<OwnedHandle>) -> T {
1180 file.into().into()
1181}
1182
1183const DEFAULT_BUF_SIZE: usize = 8192;
1184
1185pub fn copy_with_signals(
1186 mut reader: impl Read,
1187 mut writer: impl Write,
1188 span: Span,
1189 signals: &Signals,
1190) -> Result<u64, ShellError> {
1191 let from_io_error = IoError::factory(span, None);
1192 if signals.is_empty() {
1193 match io::copy(&mut reader, &mut writer) {
1194 Ok(n) => {
1195 writer.flush().map_err(&from_io_error)?;
1196 Ok(n)
1197 }
1198 Err(err) => {
1199 let _ = writer.flush();
1200 match ShellErrorBridge::try_from(err) {
1201 Ok(ShellErrorBridge(shell_error)) => Err(shell_error),
1202 Err(err) => Err(from_io_error(err).into()),
1203 }
1204 }
1205 }
1206 } else {
1207 match generic_copy(&mut reader, &mut writer, span, signals) {
1212 Ok(len) => {
1213 writer.flush().map_err(&from_io_error)?;
1214 Ok(len)
1215 }
1216 Err(err) => {
1217 let _ = writer.flush();
1218 Err(err)
1219 }
1220 }
1221 }
1222}
1223
1224fn generic_copy(
1226 mut reader: impl Read,
1227 mut writer: impl Write,
1228 span: Span,
1229 signals: &Signals,
1230) -> Result<u64, ShellError> {
1231 let from_io_error = IoError::factory(span, None);
1232 let buf = &mut [0; DEFAULT_BUF_SIZE];
1233 let mut len = 0;
1234 loop {
1235 signals.check(&span)?;
1236 let n = match reader.read(buf) {
1237 Ok(0) => break,
1238 Ok(n) => n,
1239 Err(e) if e.kind() == ErrorKind::Interrupted => continue,
1240 Err(e) => match ShellErrorBridge::try_from(e) {
1241 Ok(ShellErrorBridge(e)) => return Err(e),
1242 Err(e) => return Err(from_io_error(e).into()),
1243 },
1244 };
1245 len += n;
1246 writer.write_all(&buf[..n]).map_err(&from_io_error)?;
1247 }
1248 Ok(len as u64)
1249}
1250
1251struct ReadGenerator<F>
1252where
1253 F: FnMut(&mut Vec<u8>) -> Result<bool, ShellError> + Send + 'static,
1254{
1255 buffer: Cursor<Vec<u8>>,
1256 generator: F,
1257}
1258
1259impl<F> BufRead for ReadGenerator<F>
1260where
1261 F: FnMut(&mut Vec<u8>) -> Result<bool, ShellError> + Send + 'static,
1262{
1263 fn fill_buf(&mut self) -> std::io::Result<&[u8]> {
1264 while self.buffer.fill_buf()?.is_empty() {
1267 self.buffer.set_position(0);
1269 self.buffer.get_mut().clear();
1270 if !(self.generator)(self.buffer.get_mut()).map_err(ShellErrorBridge)? {
1272 break;
1274 }
1275 }
1276 self.buffer.fill_buf()
1277 }
1278
1279 fn consume(&mut self, amt: usize) {
1280 self.buffer.consume(amt);
1281 }
1282}
1283
1284impl<F> Read for ReadGenerator<F>
1285where
1286 F: FnMut(&mut Vec<u8>) -> Result<bool, ShellError> + Send + 'static,
1287{
1288 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
1289 let slice = self.fill_buf()?;
1291 let len = buf.len().min(slice.len());
1292 buf[..len].copy_from_slice(&slice[..len]);
1293 self.consume(len);
1294 Ok(len)
1295 }
1296}
1297
1298#[cfg(test)]
1299mod tests {
1300 use super::*;
1301 use nu_utils::SharedCow;
1302
1303 fn test_chunks<T>(data: Vec<T>, type_: ByteStreamType) -> Chunks
1304 where
1305 T: AsRef<[u8]> + Default + Send + 'static,
1306 {
1307 let reader = ReadIterator {
1308 iter: data.into_iter(),
1309 cursor: Some(Cursor::new(T::default())),
1310 };
1311 Chunks::new(
1312 SourceReader::Read(Box::new(reader)),
1313 Span::test_data(),
1314 Signals::empty(),
1315 type_,
1316 )
1317 }
1318
1319 #[test]
1320 fn chunks_read_binary_passthrough() {
1321 let bins = vec![&[0, 1][..], &[2, 3][..]];
1322 let iter = test_chunks(bins.clone(), ByteStreamType::Binary);
1323
1324 let bins_values: Vec<Value> = bins
1325 .into_iter()
1326 .map(|bin| Value::binary(bin, Span::test_data()))
1327 .collect();
1328 assert_eq!(
1329 bins_values,
1330 iter.collect::<Result<Vec<Value>, _>>().expect("error")
1331 );
1332 }
1333
1334 #[test]
1335 fn read_binary_shares_data() {
1336 let data = SharedCow::new(vec![0, 1, 2, 3]);
1337 let stream = ByteStream::read_binary(data.clone(), Span::test_data(), Signals::empty());
1338
1339 assert_eq!(SharedCow::ref_count(&data), 2);
1340 assert_eq!(stream.into_bytes().expect("error"), data.as_slice());
1341 }
1342
1343 #[test]
1344 fn chunks_read_string_clean() {
1345 let strs = vec!["Nushell", "が好きです"];
1346 let iter = test_chunks(strs.clone(), ByteStreamType::String);
1347
1348 let strs_values: Vec<Value> = strs
1349 .into_iter()
1350 .map(|string| Value::string(string, Span::test_data()))
1351 .collect();
1352 assert_eq!(
1353 strs_values,
1354 iter.collect::<Result<Vec<Value>, _>>().expect("error")
1355 );
1356 }
1357
1358 #[test]
1359 fn chunks_read_string_split_boundary() {
1360 let real = "Nushell最高!";
1361 let chunks = vec![&b"Nushell\xe6"[..], &b"\x9c\x80\xe9"[..], &b"\xab\x98!"[..]];
1362 let iter = test_chunks(chunks.clone(), ByteStreamType::String);
1363
1364 let mut string = String::new();
1365 for value in iter {
1366 let chunk_string = value.expect("error").into_string().expect("not a string");
1367 string.push_str(&chunk_string);
1368 }
1369 assert_eq!(real, string);
1370 }
1371
1372 #[test]
1373 fn chunks_read_string_utf8_error() {
1374 let chunks = vec![&b"Nushell\xe6"[..], &b"\x9c\x80\xe9"[..], &b"\xab"[..]];
1375 let iter = test_chunks(chunks, ByteStreamType::String);
1376
1377 let mut string = String::new();
1378 for value in iter {
1379 match value {
1380 Ok(value) => string.push_str(&value.into_string().expect("not a string")),
1381 Err(err) => {
1382 println!("string so far: {string:?}");
1383 println!("got error: {err:?}");
1384 assert!(!string.is_empty());
1385 assert!(matches!(err, ShellError::NonUtf8Custom { .. }));
1386 return;
1387 }
1388 }
1389 }
1390 panic!("no error");
1391 }
1392
1393 #[test]
1394 fn chunks_read_unknown_fallback() {
1395 let chunks = vec![&b"Nushell"[..], &b"\x9c\x80\xe9abcd"[..], &b"efgh"[..]];
1396 let mut iter = test_chunks(chunks, ByteStreamType::Unknown);
1397
1398 let mut get = || iter.next().expect("end of iter").expect("error");
1399
1400 assert_eq!(Value::test_string("Nushell"), get());
1401 assert_eq!(Value::test_binary(b"\x9c\x80\xe9abcd"), get());
1402 assert_eq!(Value::test_binary(b"efgh"), get());
1404 }
1405}