@@ -397,33 +397,11 @@ pub fn from_reader<R: std::io::Read + ?Sized>(
397 let mut buf_out = [0u8; BUF_SIZE];
397 let mut buf_out = [0u8; BUF_SIZE];
398 let mut builder = RopeBuilder::new();
398 let mut builder = RopeBuilder::new();
400− // By default, the encoding of the text is auto-detected by
401− // `encoding_rs` for_bom, and if it fails, from `chardetng`
402− // crate which requires sample data from the reader.
403− // As a manual override to this auto-detection is possible, the
404− // same data is read into `buf` to ensure symmetry in the upcoming
406− let (encoding, has_bom, mut decoder, mut slice, mut is_empty) = {
400+ let (encoding, has_bom, mut decoder, read) =
407− let read = reader.read(&mut buf)?;
401+ read_and_detect_encoding(reader, encoding, &mut buf)?;
408− let is_empty = read == 0;
409− let (encoding, has_bom) = encoding
410− .map(|encoding| (encoding, false))
412− encoding::Encoding::for_bom(&buf).map(|(encoding, _bom_size)| (encoding, true))
414− .unwrap_or_else(|| {
415− let mut encoding_detector = chardetng::EncodingDetector::new();
416− encoding_detector.feed(&buf, is_empty);
417− (encoding_detector.guess(None, true), false)
420− let decoder = encoding.new_decoder();
422− // If the amount of bytes read from the reader is less than
423− // `buf.len()`, it is undesirable to read the bytes afterwards.
424− let slice = &buf[..read];
403+ let mut slice = &buf[..read];
425− (encoding, has_bom, decoder, slice, is_empty)
404+ let mut is_empty = read == 0;
428 // `RopeBuilder::append()` expects a `&str`, so this is the "real"
406 // `RopeBuilder::append()` expects a `&str`, so this is the "real"
429 // output buffer. When decoding, the number of bytes in the output
407 // output buffer. When decoding, the number of bytes in the output
@@ -493,6 +471,81 @@ pub fn from_reader<R: std::io::Read + ?Sized>(
493 Ok((rope, encoding, has_bom))
471 Ok((rope, encoding, has_bom))
474+pub fn read_to_string<R: std::io::Read + ?Sized>(
476+ encoding: Option<&'static Encoding>,
477+) -> Result<(String, &'static Encoding, bool), Error> {
478+ let mut buf = [0u8; BUF_SIZE];
480+ let (encoding, has_bom, mut decoder, read) =
481+ read_and_detect_encoding(reader, encoding, &mut buf)?;
483+ let mut slice = &buf[..read];
484+ let mut is_empty = read == 0;
485+ let mut buf_string = String::with_capacity(buf.len());
488+ let mut total_read = 0usize;
491+ let (result, read, ..) =
492+ decoder.decode_to_string(&slice[total_read..], &mut buf_string, is_empty);
497+ encoding::CoderResult::InputEmpty => {
498+ debug_assert_eq!(slice.len(), total_read);
501+ encoding::CoderResult::OutputFull => {
502+ debug_assert!(slice.len() > total_read);
503+ buf_string.reserve(buf.len())
509+ debug_assert_eq!(reader.read(&mut buf)?, 0);
513+ let read = reader.read(&mut buf)?;
514+ slice = &buf[..read];
515+ is_empty = read == 0;
517+ Ok((buf_string, encoding, has_bom))
520+/// Reads the first chunk from a Reader into the given buffer
521+/// and detects the encoding.
523+/// By default, the encoding of the text is auto-detected by
524+/// `encoding_rs` for_bom, and if it fails, from `chardetng`
525+/// crate which requires sample data from the reader.
526+/// As a manual override to this auto-detection is possible, the
527+/// same data is read into `buf` to ensure symmetry in the upcoming
529+fn read_and_detect_encoding<R: std::io::Read + ?Sized>(
531+ encoding: Option<&'static Encoding>,
533+) -> Result<(&'static Encoding, bool, encoding::Decoder, usize), Error> {
534+ let read = reader.read(buf)?;
535+ let is_empty = read == 0;
536+ let (encoding, has_bom) = encoding
537+ .map(|encoding| (encoding, false))
538+ .or_else(|| encoding::Encoding::for_bom(buf).map(|(encoding, _bom_size)| (encoding, true)))
539+ .unwrap_or_else(|| {
540+ let mut encoding_detector = chardetng::EncodingDetector::new();
541+ encoding_detector.feed(buf, is_empty);
542+ (encoding_detector.guess(None, true), false)
544+ let decoder = encoding.new_decoder();
546+ Ok((encoding, has_bom, decoder, read))
496// The documentation and implementation of this function should be up-to-date with
549// The documentation and implementation of this function should be up-to-date with
497// its sibling function, `from_reader()`.
550// its sibling function, `from_reader()`.