<commit_before>use std::marker::PhantomData;

use query::Operand;
use perlin_core::index::posting::DocId;

pub type Pipeline<Out, T> = Box<Fn(DocId, &mut T, &str) -> PhantomData<Out> + Sync + Send>;
pub type QueryPipeline<T> = Box<for<'r, 'x> Fn(&'r T, &'x str) -> Operand<'r> + Sync + Send>;

#[cfg(test)]
mod tests {
    use perlin_core::index::posting::DocId;
    use field::Field;

    use rust_stemmers::Algorithm;

    use test_utils::create_test_dir;

    #[derive(PerlinDocument)]
    pub struct Test {
        text: Field<String>,
        title: Field<String>,
        #[NoPipe]
        number: Field<u64>,
        #[NoPipe]
        emails: Field<usize>,
    }

    use language::{Stemmer, LowercaseFilter, WhitespaceTokenizer};
    use language::integers::NumberFilter;
    use std::borrow::Cow;
    use perlin_core::index::posting::Posting;

    fn create_and_fill_index(name: &str) -> TestIndex {
        let mut t = TestIndex::create(create_test_dir(name));
        t.set_text_pipeline(pipeline!(text
                           WhitespaceTokenizer
                           > NumberFilter
                             | [number]
                           > LowercaseFilter
                           > Stemmer(Algorithm::English)));
        t.set_title_pipeline(pipeline!(title
                                       WhitespaceTokenizer
                                       > LowercaseFilter
                                       > Stemmer(Algorithm::English)));
        t.set_query_pipeline(query_pipeline!(
            WhitespaceTokenizer
                > NumberFilter
                | Must [Any in number]
                > LowercaseFilter
                > Stemmer(Algorithm::English)
                > Must [All in text]
        ));
        t.add_document(&[(Cow::from("text"), Cow::from("10 birds flew over MT EVEREST"))]);
        t.add_document(&[(Cow::from("text"), Cow::from("125 birds flew accross THE ocean"))]);
        t.add_document(&[(Cow::from("title"), Cow::from("Unicorns on Deimos")),
                         (Cow::from("text"),
                          Cow::from("2567 unicorns flew from phobos to deimos"))]);
        t.commit();
        t
    }

    fn should_yield(index: &TestIndex, query: &str, ids: &[u64]) {
        if index.run_query(query).collect::<Vec<_>>() !=
           ids.iter().map(|id| Posting(DocId(*id))).collect::<Vec<_>>() {
            assert!(false,
                    format!("{} resulted in {:?} expexted {:?}",
                            query,
                            index.run_query(query).collect::<Vec<_>>(),
                            ids.iter().map(|id| Posting(DocId(*id))).collect::<Vec<_>>()))
        }
    }

    #[test]
    #[should_panic]
    fn negative_test() {
        let t = create_and_fill_index("doc_index/negative_test");
        should_yield(&t, "10 deimos", &[]);
        should_yield(&t, "2567 deimos", &[22]);
    }

    #[test]
    fn basic_test() {
        let t = create_and_fill_index("doc_index/basic_test");
        should_yield(&t, "10 deimos", &[]);
        should_yield(&t, "2567 deimos", &[2]);
    }

    #[test]
    fn empty_query() {
        let mut t = create_and_fill_index("doc_index/empty");
        t.set_query_pipeline(query_pipeline!(
            WhitespaceTokenizer
                > NumberFilter
                | Must [Any in number]
                > LowercaseFilter
                > Stemmer(Algorithm::English)
                > Must [Any in title]));
        // No term to funnel -> no operator -> only numberfunnel returns
        should_yield(&t, "10", &[0]);
        // Unkown term to funnel -> empty iterator -> empty result
        should_yield(&t, "10 pizza", &[]);
        should_yield(&t, "deimos", &[2]);
    }

    #[test]
    fn nested_query() {
        let mut t = create_and_fill_index("doc_index/nested");
        t.set_query_pipeline(query_pipeline!(
            WhitespaceTokenizer
                > NumberFilter
                | Must [Any in number]
                > LowercaseFilter
                > Stemmer(Algorithm::English)
                > Must [Any in title]
                > Must [All in text]));
        should_yield(&t, "2567 deimos phobos", &[2]);
        should_yield(&t, "deimos phobos", &[2]);
        should_yield(&t, "ocean", &[]);
    }
}
<commit_msg>fix no_pipe<commit_after>use std::marker::PhantomData;

use query::Operand;
use perlin_core::index::posting::DocId;

pub type Pipeline<Out, T> = Box<Fn(DocId, &mut T, &str) -> PhantomData<Out> + Sync + Send>;
pub type QueryPipeline<T> = Box<for<'r, 'x> Fn(&'r T, &'x str) -> Operand<'r> + Sync + Send>;

#[cfg(test)]
mod tests {
    use perlin_core::index::posting::DocId;
    use field::Field;

    use rust_stemmers::Algorithm;

    use test_utils::create_test_dir;

    #[derive(PerlinDocument)]
    pub struct Test {
        text: Field<String>,
        title: Field<String>,
        #[no_pipe]
        number: Field<u64>,
        #[no_pipe]
        emails: Field<usize>,
    }

    use language::{Stemmer, LowercaseFilter, WhitespaceTokenizer};
    use language::integers::NumberFilter;
    use std::borrow::Cow;
    use perlin_core::index::posting::Posting;

    fn create_and_fill_index(name: &str) -> TestIndex {
        let mut t = TestIndex::create(create_test_dir(name));
        t.set_text_pipeline(pipeline!(text
                           WhitespaceTokenizer
                           > NumberFilter
                             | [number]
                           > LowercaseFilter
                           > Stemmer(Algorithm::English)));
        t.set_title_pipeline(pipeline!(title
                                       WhitespaceTokenizer
                                       > LowercaseFilter
                                       > Stemmer(Algorithm::English)));
        t.set_query_pipeline(query_pipeline!(
            WhitespaceTokenizer
                > NumberFilter
                | Must [Any in number]
                > LowercaseFilter
                > Stemmer(Algorithm::English)
                > Must [All in text]
        ));
        t.add_document(&[(Cow::from("text"), Cow::from("10 birds flew over MT EVEREST"))]);
        t.add_document(&[(Cow::from("text"), Cow::from("125 birds flew accross THE ocean"))]);
        t.add_document(&[(Cow::from("title"), Cow::from("Unicorns on Deimos")),
                         (Cow::from("text"),
                          Cow::from("2567 unicorns flew from phobos to deimos"))]);
        t.commit();
        t
    }

    fn should_yield(index: &TestIndex, query: &str, ids: &[u64]) {
        if index.run_query(query).collect::<Vec<_>>() !=
           ids.iter().map(|id| Posting(DocId(*id))).collect::<Vec<_>>() {
            assert!(false,
                    format!("{} resulted in {:?} expexted {:?}",
                            query,
                            index.run_query(query).collect::<Vec<_>>(),
                            ids.iter().map(|id| Posting(DocId(*id))).collect::<Vec<_>>()))
        }
    }

    #[test]
    #[should_panic]
    fn negative_test() {
        let t = create_and_fill_index("doc_index/negative_test");
        should_yield(&t, "10 deimos", &[]);
        should_yield(&t, "2567 deimos", &[22]);
    }

    #[test]
    fn basic_test() {
        let t = create_and_fill_index("doc_index/basic_test");
        should_yield(&t, "10 deimos", &[]);
        should_yield(&t, "2567 deimos", &[2]);
    }

    #[test]
    fn empty_query() {
        let mut t = create_and_fill_index("doc_index/empty");
        t.set_query_pipeline(query_pipeline!(
            WhitespaceTokenizer
                > NumberFilter
                | Must [Any in number]
                > LowercaseFilter
                > Stemmer(Algorithm::English)
                > Must [Any in title]));
        // No term to funnel -> no operator -> only numberfunnel returns
        should_yield(&t, "10", &[0]);
        // Unkown term to funnel -> empty iterator -> empty result
        should_yield(&t, "10 pizza", &[]);
        should_yield(&t, "deimos", &[2]);
    }

    #[test]
    fn nested_query() {
        let mut t = create_and_fill_index("doc_index/nested");
        t.set_query_pipeline(query_pipeline!(
            WhitespaceTokenizer
                > NumberFilter
                | Must [Any in number]
                > LowercaseFilter
                > Stemmer(Algorithm::English)
                > Must [Any in title]
                > Must [All in text]));
        should_yield(&t, "2567 deimos phobos", &[2]);
        should_yield(&t, "deimos phobos", &[2]);
        should_yield(&t, "ocean", &[]);
    }
}
<|endoftext|>


<commit_before>//! Formatting for the time crate.

pub(crate) mod formattable;

use std::io;

use crate::format_description::{modifier, Component};
use crate::{error, Date, Time, UtcOffset};

#[allow(clippy::clippy::missing_docs_in_private_items)]
const MONTH_NAMES: [&str; 12] = [
    "January",
    "February",
    "March",
    "April",
    "May",
    "June",
    "July",
    "August",
    "September",
    "October",
    "November",
    "December",
];

#[allow(clippy::missing_docs_in_private_items)]
const WEEKDAY_NAMES: [&str; 7] = [
    "Monday",
    "Tuesday",
    "Wednesday",
    "Thursday",
    "Friday",
    "Saturday",
    "Sunday",
];

/// A trait that indicates the formatted width of the value can be determined.
///
/// Note that this should not be implemented for any signed integers. This forces the caller to
/// write the sign if desired.
pub(crate) trait DigitCount {
    /// The number of digits in the stringified value.
    fn num_digits(self) -> u8;
}
impl DigitCount for u8 {
    fn num_digits(self) -> u8 {
        if self < 10 {
            1
        } else if self < 100 {
            2
        } else {
            3
        }
    }
}
impl DigitCount for u16 {
    fn num_digits(self) -> u8 {
        if self < 10 {
            1
        } else if self < 100 {
            2
        } else if self < 1_000 {
            3
        } else if self < 10_000 {
            4
        } else {
            5
        }
    }
}
impl DigitCount for u32 {
    fn num_digits(self) -> u8 {
        if self < 10 {
            1
        } else if self < 100 {
            2
        } else if self < 1_000 {
            3
        } else if self < 10_000 {
            4
        } else if self < 100_000 {
            5
        } else if self < 1_000_000 {
            6
        } else if self < 10_000_000 {
            7
        } else if self < 100_000_000 {
            8
        } else if self < 1_000_000_000 {
            9
        } else {
            10
        }
    }
}

/// Format a number with the provided padding and width.
///
/// The sign must be written by the caller.
pub(crate) fn format_number(
    output: &mut impl io::Write,
    value: impl itoa::Integer + DigitCount + Copy,
    padding: modifier::Padding,
    width: u8,
) -> Result<usize, io::Error> {
    match padding {
        modifier::Padding::Space => {
            let mut bytes = 0;
            for _ in 0..(width.saturating_sub(value.num_digits())) {
                bytes += output.write(&[b' '])?;
            }
            bytes += itoa::write(output, value)?;
            Ok(bytes)
        }
        modifier::Padding::Zero => {
            let mut bytes = 0;
            for _ in 0..(width.saturating_sub(value.num_digits())) {
                bytes += output.write(&[b'0'])?;
            }
            bytes += itoa::write(output, value)?;
            Ok(bytes)
        }
        modifier::Padding::None => itoa::write(output, value),
    }
}

/// Format the provided component into the designated output. An `Err` will be returned if the
/// component requires information that it does not provide or if the value cannot be output to the
/// stream.
#[allow(clippy::too_many_lines, clippy::cognitive_complexity)]
pub(crate) fn format_component(
    output: &mut impl io::Write,
    component: Component,
    date: Option<Date>,
    time: Option<Time>,
    offset: Option<UtcOffset>,
) -> Result<usize, error::Format> {
    Ok(match (component, date, time, offset) {
        (Component::Day(modifier::Day { padding }), Some(date), ..) => {
            format_number(output, date.day(), padding, 2)?
        }
        (Component::Month(modifier::Month { padding, repr }), Some(date), ..) => match repr {
            modifier::MonthRepr::Numerical => format_number(output, date.month(), padding, 2)?,
            modifier::MonthRepr::Long => {
                output.write(MONTH_NAMES[date.month() as usize - 1].as_bytes())?
            }
            modifier::MonthRepr::Short => {
                output.write(MONTH_NAMES[date.month() as usize - 1][..3].as_bytes())?
            }
        },
        (Component::Ordinal(modifier::Ordinal { padding }), Some(date), ..) => {
            format_number(output, date.ordinal(), padding, 3)?
        }
        (Component::Weekday(modifier::Weekday { repr, one_indexed }), Some(date), ..) => match repr
        {
            modifier::WeekdayRepr::Short => output.write(
                WEEKDAY_NAMES[date.weekday().number_days_from_monday() as usize][..3].as_bytes(),
            )?,
            modifier::WeekdayRepr::Long => output.write(
                WEEKDAY_NAMES[date.weekday().number_days_from_monday() as usize].as_bytes(),
            )?,
            modifier::WeekdayRepr::Sunday => format_number(
                output,
                date.weekday().number_days_from_sunday() + one_indexed as u8,
                modifier::Padding::None,
                1,
            )?,
            modifier::WeekdayRepr::Monday => format_number(
                output,
                date.weekday().number_days_from_monday() + one_indexed as u8,
                modifier::Padding::None,
                1,
            )?,
        },
        (Component::WeekNumber(modifier::WeekNumber { padding, repr }), Some(date), ..) => {
            format_number(
                output,
                match repr {
                    modifier::WeekNumberRepr::Iso => date.iso_week(),
                    modifier::WeekNumberRepr::Sunday => date.sunday_based_week(),
                    modifier::WeekNumberRepr::Monday => date.monday_based_week(),
                },
                padding,
                2,
            )?
        }
        (
            Component::Year(modifier::Year {
                padding,
                repr,
                iso_week_based,
                sign_is_mandatory,
            }),
            Some(date),
            ..,
        ) => {
            let full_year = if iso_week_based {
                date.iso_year_week().0
            } else {
                date.year()
            };

            let value = match repr {
                modifier::YearRepr::Full => full_year,
                modifier::YearRepr::LastTwo => (full_year % 100).abs(),
            };

            let width = match repr {
                #[cfg(feature = "large-dates")]
                modifier::YearRepr::Full if value.abs() >= 100_000 => 6,
                #[cfg(feature = "large-dates")]
                modifier::YearRepr::Full if value.abs() >= 10_000 => 5,
                modifier::YearRepr::Full => 4,
                modifier::YearRepr::LastTwo => 2,
            };

            let mut bytes = 0;

            // Don't emit a sign when only displaying the last two digits.
            if repr != modifier::YearRepr::LastTwo {
                if full_year < 0 {
                    bytes += output.write(&[b'-'])?;
                } else if sign_is_mandatory || cfg!(feature = "large-dates") && full_year >= 10_000
                {
                    bytes += output.write(&[b'+'])?;
                }
            }

            bytes += format_number(output, value.abs() as u32, padding, width)?;
            bytes
        }
        (
            Component::Hour(modifier::Hour {
                padding,
                is_12_hour_clock,
            }),
            _,
            Some(time),
            _,
        ) => {
            let value = match (time.hour, is_12_hour_clock) {
                (hour, false) => hour,
                (0, true) | (12, true) => 12,
                (hour, true) if hour < 12 => hour,
                (hour, true) => hour - 12,
            };
            format_number(output, value, padding, 2)?
        }
        (Component::Minute(modifier::Minute { padding }), _, Some(time), _) => {
            format_number(output, time.minute, padding, 2)?
        }
        (Component::Period(modifier::Period { is_uppercase }), _, Some(time), _) => {
            match (time.hour >= 12, is_uppercase) {
                (false, false) => output.write(b"am"),
                (false, true) => output.write(b"AM"),
                (true, false) => output.write(b"pm"),
                (true, true) => output.write(b"PM"),
            }?
        }
        (Component::Second(modifier::Second { padding }), _, Some(time), _) => {
            format_number(output, time.second, padding, 2)?
        }
        (Component::Subsecond(modifier::Subsecond { digits }), _, Some(time), _) => {
            let (value, width) = match digits {
                modifier::SubsecondDigits::One => (time.nanosecond / 100_000_000, 1),
                modifier::SubsecondDigits::Two => (time.nanosecond / 10_000_000, 2),
                modifier::SubsecondDigits::Three => (time.nanosecond / 1_000_000, 3),
                modifier::SubsecondDigits::Four => (time.nanosecond / 100_000, 4),
                modifier::SubsecondDigits::Five => (time.nanosecond / 10_000, 5),
                modifier::SubsecondDigits::Six => (time.nanosecond / 1_000, 6),
                modifier::SubsecondDigits::Seven => (time.nanosecond / 100, 7),
                modifier::SubsecondDigits::Eight => (time.nanosecond / 10, 8),
                modifier::SubsecondDigits::Nine => (time.nanosecond, 9),
                modifier::SubsecondDigits::OneOrMore => match time.nanosecond {
                    nanos if nanos % 10 != 0 => (nanos, 9),
                    nanos if (nanos / 10) % 10 != 0 => (nanos / 10, 8),
                    nanos if (nanos / 100) % 10 != 0 => (nanos / 100, 7),
                    nanos if (nanos / 1_000) % 10 != 0 => (nanos / 1_000, 6),
                    nanos if (nanos / 10_000) % 10 != 0 => (nanos / 10_000, 5),
                    nanos if (nanos / 100_000) % 10 != 0 => (nanos / 100_000, 4),
                    nanos if (nanos / 1_000_000) % 10 != 0 => (nanos / 1_000_000, 3),
                    nanos if (nanos / 10_000_000) % 10 != 0 => (nanos / 10_000_000, 2),
                    nanos => (nanos / 100_000_000, 1),
                },
            };
            format_number(output, value, modifier::Padding::Zero, width)?
        }
        (
            Component::OffsetHour(modifier::OffsetHour {
                padding,
                sign_is_mandatory,
            }),
            _,
            _,
            Some(offset),
        ) => {
            let mut bytes = 0;
            if offset.is_negative() {
                bytes += output.write(&[b'-'])?;
            } else if sign_is_mandatory {
                bytes += output.write(&[b'+'])?;
            }
            bytes += format_number(output, offset.hours.abs() as u8, padding, 2)?;
            bytes
        }
        (Component::OffsetMinute(modifier::OffsetMinute { padding }), _, _, Some(offset)) => {
            format_number(output, offset.minutes.abs() as u8, padding, 2)?
        }

        (Component::OffsetSecond(modifier::OffsetSecond { padding }), _, _, Some(offset)) => {
            format_number(output, offset.seconds.abs() as u8, padding, 2)?
        }
        _ => return Err(error::Format::InsufficientTypeInformation),
    })
}
<commit_msg>Extract functions from `format_component`<commit_after>//! Formatting for the time crate.

pub(crate) mod formattable;

use std::io;

use crate::format_description::{modifier, Component};
use crate::{error, Date, Time, UtcOffset};

#[allow(clippy::clippy::missing_docs_in_private_items)]
const MONTH_NAMES: [&str; 12] = [
    "January",
    "February",
    "March",
    "April",
    "May",
    "June",
    "July",
    "August",
    "September",
    "October",
    "November",
    "December",
];

#[allow(clippy::missing_docs_in_private_items)]
const WEEKDAY_NAMES: [&str; 7] = [
    "Monday",
    "Tuesday",
    "Wednesday",
    "Thursday",
    "Friday",
    "Saturday",
    "Sunday",
];

/// A trait that indicates the formatted width of the value can be determined.
///
/// Note that this should not be implemented for any signed integers. This forces the caller to
/// write the sign if desired.
pub(crate) trait DigitCount {
    /// The number of digits in the stringified value.
    fn num_digits(self) -> u8;
}
impl DigitCount for u8 {
    fn num_digits(self) -> u8 {
        if self < 10 {
            1
        } else if self < 100 {
            2
        } else {
            3
        }
    }
}
impl DigitCount for u16 {
    fn num_digits(self) -> u8 {
        if self < 10 {
            1
        } else if self < 100 {
            2
        } else if self < 1_000 {
            3
        } else if self < 10_000 {
            4
        } else {
            5
        }
    }
}
impl DigitCount for u32 {
    fn num_digits(self) -> u8 {
        if self < 10 {
            1
        } else if self < 100 {
            2
        } else if self < 1_000 {
            3
        } else if self < 10_000 {
            4
        } else if self < 100_000 {
            5
        } else if self < 1_000_000 {
            6
        } else if self < 10_000_000 {
            7
        } else if self < 100_000_000 {
            8
        } else if self < 1_000_000_000 {
            9
        } else {
            10
        }
    }
}

/// Format a number with the provided padding and width.
///
/// The sign must be written by the caller.
pub(crate) fn format_number(
    output: &mut impl io::Write,
    value: impl itoa::Integer + DigitCount + Copy,
    padding: modifier::Padding,
    width: u8,
) -> Result<usize, io::Error> {
    match padding {
        modifier::Padding::Space => {
            let mut bytes = 0;
            for _ in 0..(width.saturating_sub(value.num_digits())) {
                bytes += output.write(&[b' '])?;
            }
            bytes += itoa::write(output, value)?;
            Ok(bytes)
        }
        modifier::Padding::Zero => {
            let mut bytes = 0;
            for _ in 0..(width.saturating_sub(value.num_digits())) {
                bytes += output.write(&[b'0'])?;
            }
            bytes += itoa::write(output, value)?;
            Ok(bytes)
        }
        modifier::Padding::None => itoa::write(output, value),
    }
}

/// Format the provided component into the designated output. An `Err` will be returned if the
/// component requires information that it does not provide or if the value cannot be output to the
/// stream.
pub(crate) fn format_component(
    output: &mut impl io::Write,
    component: Component,
    date: Option<Date>,
    time: Option<Time>,
    offset: Option<UtcOffset>,
) -> Result<usize, error::Format> {
    use Component::*;
    Ok(match (component, date, time, offset) {
        (Day(modifier), Some(date), ..) => fmt_day(output, date, modifier)?,
        (Month(modifier), Some(date), ..) => fmt_month(output, date, modifier)?,
        (Ordinal(modifier), Some(date), ..) => fmt_ordinal(output, date, modifier)?,
        (Weekday(modifier), Some(date), ..) => fmt_weekday(output, date, modifier)?,
        (WeekNumber(modifier), Some(date), ..) => fmt_week_number(output, date, modifier)?,
        (Year(modifier), Some(date), ..) => fmt_year(output, date, modifier)?,
        (Hour(modifier), _, Some(time), _) => fmt_hour(output, time, modifier)?,
        (Minute(modifier), _, Some(time), _) => fmt_minute(output, time, modifier)?,
        (Period(modifier), _, Some(time), _) => fmt_period(output, time, modifier)?,
        (Second(modifier), _, Some(time), _) => fmt_second(output, time, modifier)?,
        (Subsecond(modifier), _, Some(time), _) => fmt_subsecond(output, time, modifier)?,
        (OffsetHour(modifier), .., Some(offset)) => fmt_offset_hour(output, offset, modifier)?,
        (OffsetMinute(modifier), .., Some(offset)) => fmt_offset_minute(output, offset, modifier)?,
        (OffsetSecond(modifier), .., Some(offset)) => fmt_offset_second(output, offset, modifier)?,
        _ => return Err(error::Format::InsufficientTypeInformation),
    })
}

/// Format the day into the designated output.
fn fmt_day(
    output: &mut impl io::Write,
    date: Date,
    modifier::Day { padding }: modifier::Day,
) -> Result<usize, io::Error> {
    format_number(output, date.day(), padding, 2)
}

/// Format the month into the designated output.
fn fmt_month(
    output: &mut impl io::Write,
    date: Date,
    modifier::Month { padding, repr }: modifier::Month,
) -> Result<usize, io::Error> {
    match repr {
        modifier::MonthRepr::Numerical => format_number(output, date.month(), padding, 2),
        modifier::MonthRepr::Long => {
            output.write(MONTH_NAMES[date.month() as usize - 1].as_bytes())
        }
        modifier::MonthRepr::Short => {
            output.write(MONTH_NAMES[date.month() as usize - 1][..3].as_bytes())
        }
    }
}

/// Format the ordinal into the designated output.
fn fmt_ordinal(
    output: &mut impl io::Write,
    date: Date,
    modifier::Ordinal { padding }: modifier::Ordinal,
) -> Result<usize, io::Error> {
    format_number(output, date.ordinal(), padding, 3)
}

/// Format the weekday into the designated output.
fn fmt_weekday(
    output: &mut impl io::Write,
    date: Date,
    modifier::Weekday { repr, one_indexed }: modifier::Weekday,
) -> Result<usize, io::Error> {
    match repr {
        modifier::WeekdayRepr::Short => output.write(
            WEEKDAY_NAMES[date.weekday().number_days_from_monday() as usize][..3].as_bytes(),
        ),
        modifier::WeekdayRepr::Long => output
            .write(WEEKDAY_NAMES[date.weekday().number_days_from_monday() as usize].as_bytes()),
        modifier::WeekdayRepr::Sunday => format_number(
            output,
            date.weekday().number_days_from_sunday() + one_indexed as u8,
            modifier::Padding::None,
            1,
        ),
        modifier::WeekdayRepr::Monday => format_number(
            output,
            date.weekday().number_days_from_monday() + one_indexed as u8,
            modifier::Padding::None,
            1,
        ),
    }
}

/// Format the week number into the designated output.
fn fmt_week_number(
    output: &mut impl io::Write,
    date: Date,
    modifier::WeekNumber { padding, repr }: modifier::WeekNumber,
) -> Result<usize, io::Error> {
    format_number(
        output,
        match repr {
            modifier::WeekNumberRepr::Iso => date.iso_week(),
            modifier::WeekNumberRepr::Sunday => date.sunday_based_week(),
            modifier::WeekNumberRepr::Monday => date.monday_based_week(),
        },
        padding,
        2,
    )
}

/// Format the year into the designated output.
fn fmt_year(
    output: &mut impl io::Write,
    date: Date,
    modifier::Year {
        padding,
        repr,
        iso_week_based,
        sign_is_mandatory,
    }: modifier::Year,
) -> Result<usize, io::Error> {
    let full_year = if iso_week_based {
        date.iso_year_week().0
    } else {
        date.year()
    };
    let value = match repr {
        modifier::YearRepr::Full => full_year,
        modifier::YearRepr::LastTwo => (full_year % 100).abs(),
    };
    let width = match repr {
        #[cfg(feature = "large-dates")]
        modifier::YearRepr::Full if value.abs() >= 100_000 => 6,
        #[cfg(feature = "large-dates")]
        modifier::YearRepr::Full if value.abs() >= 10_000 => 5,
        modifier::YearRepr::Full => 4,
        modifier::YearRepr::LastTwo => 2,
    };
    let mut bytes = 0;
    if repr != modifier::YearRepr::LastTwo {
        if full_year < 0 {
            bytes += output.write(&[b'-'])?;
        } else if sign_is_mandatory || cfg!(feature = "large-dates") && full_year >= 10_000 {
            bytes += output.write(&[b'+'])?;
        }
    }
    bytes += format_number(output, value.abs() as u32, padding, width)?;
    Ok(bytes)
}

/// Format the hour into the designated output.
fn fmt_hour(
    output: &mut impl io::Write,
    time: Time,
    modifier::Hour {
        padding,
        is_12_hour_clock,
    }: modifier::Hour,
) -> Result<usize, io::Error> {
    let value = match (time.hour, is_12_hour_clock) {
        (hour, false) => hour,
        (0, true) | (12, true) => 12,
        (hour, true) if hour < 12 => hour,
        (hour, true) => hour - 12,
    };
    format_number(output, value, padding, 2)
}

/// Format the minute into the designated output.
fn fmt_minute(
    output: &mut impl io::Write,
    time: Time,
    modifier::Minute { padding }: modifier::Minute,
) -> Result<usize, io::Error> {
    format_number(output, time.minute, padding, 2)
}

/// Format the period into the designated output.
fn fmt_period(
    output: &mut impl io::Write,
    time: Time,
    modifier::Period { is_uppercase }: modifier::Period,
) -> Result<usize, io::Error> {
    match (time.hour >= 12, is_uppercase) {
        (false, false) => output.write(b"am"),
        (false, true) => output.write(b"AM"),
        (true, false) => output.write(b"pm"),
        (true, true) => output.write(b"PM"),
    }
}

/// Format the second into the designated output.
fn fmt_second(
    output: &mut impl io::Write,
    time: Time,
    modifier::Second { padding }: modifier::Second,
) -> Result<usize, io::Error> {
    format_number(output, time.second, padding, 2)
}

/// Format the subsecond into the designated output.
fn fmt_subsecond(
    output: &mut impl io::Write,
    time: Time,
    modifier::Subsecond { digits }: modifier::Subsecond,
) -> Result<usize, io::Error> {
    let (value, width) = match digits {
        modifier::SubsecondDigits::One => (time.nanosecond / 100_000_000, 1),
        modifier::SubsecondDigits::Two => (time.nanosecond / 10_000_000, 2),
        modifier::SubsecondDigits::Three => (time.nanosecond / 1_000_000, 3),
        modifier::SubsecondDigits::Four => (time.nanosecond / 100_000, 4),
        modifier::SubsecondDigits::Five => (time.nanosecond / 10_000, 5),
        modifier::SubsecondDigits::Six => (time.nanosecond / 1_000, 6),
        modifier::SubsecondDigits::Seven => (time.nanosecond / 100, 7),
        modifier::SubsecondDigits::Eight => (time.nanosecond / 10, 8),
        modifier::SubsecondDigits::Nine => (time.nanosecond, 9),
        modifier::SubsecondDigits::OneOrMore => match time.nanosecond {
            nanos if nanos % 10 != 0 => (nanos, 9),
            nanos if (nanos / 10) % 10 != 0 => (nanos / 10, 8),
            nanos if (nanos / 100) % 10 != 0 => (nanos / 100, 7),
            nanos if (nanos / 1_000) % 10 != 0 => (nanos / 1_000, 6),
            nanos if (nanos / 10_000) % 10 != 0 => (nanos / 10_000, 5),
            nanos if (nanos / 100_000) % 10 != 0 => (nanos / 100_000, 4),
            nanos if (nanos / 1_000_000) % 10 != 0 => (nanos / 1_000_000, 3),
            nanos if (nanos / 10_000_000) % 10 != 0 => (nanos / 10_000_000, 2),
            nanos => (nanos / 100_000_000, 1),
        },
    };
    format_number(output, value, modifier::Padding::Zero, width)
}

/// Format the offset hour into the designated output.
fn fmt_offset_hour(
    output: &mut impl io::Write,
    offset: UtcOffset,
    modifier::OffsetHour {
        padding,
        sign_is_mandatory,
    }: modifier::OffsetHour,
) -> Result<usize, io::Error> {
    let mut bytes = 0;
    if offset.is_negative() {
        bytes += output.write(&[b'-'])?;
    } else if sign_is_mandatory {
        bytes += output.write(&[b'+'])?;
    }
    bytes += format_number(output, offset.hours.abs() as u8, padding, 2)?;
    Ok(bytes)
}

/// Format the offset minute into the designated output.
fn fmt_offset_minute(
    output: &mut impl io::Write,
    offset: UtcOffset,
    modifier::OffsetMinute { padding }: modifier::OffsetMinute,
) -> Result<usize, io::Error> {
    format_number(output, offset.minutes.abs() as u8, padding, 2)
}

/// Format the offset second into the designated output.
fn fmt_offset_second(
    output: &mut impl io::Write,
    offset: UtcOffset,
    modifier::OffsetSecond { padding }: modifier::OffsetSecond,
) -> Result<usize, io::Error> {
    format_number(output, offset.seconds.abs() as u8, padding, 2)
}
<|endoftext|>


<commit_before>use std::future::Future;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
use std::pin::Pin;
use std::sync::Arc;
use std::task::{Context, Poll};

use crate::error::Error;
use crate::host::HostResults;
use crate::nameinfo::NameInfoResult;
use crate::resolver::{Options, Resolver};

/// The type of future returned by methods on the `FutureResolver`.
pub struct CAresFuture<T> {
    inner: futures_channel::oneshot::Receiver<c_ares::Result<T>>,
    _resolver: Arc<Resolver>,
}

impl<T> CAresFuture<T> {
    fn new(
        promise: futures_channel::oneshot::Receiver<c_ares::Result<T>>,
        resolver: Arc<Resolver>,
    ) -> Self {
        Self {
            inner: promise,
            _resolver: resolver,
        }
    }

    fn pin_get_inner(
        self: Pin<&mut Self>,
    ) -> Pin<&mut futures_channel::oneshot::Receiver<c_ares::Result<T>>> {
        unsafe { self.map_unchecked_mut(|s| &mut s.inner) }
    }
}

impl<T> Future for CAresFuture<T> {
    type Output = c_ares::Result<T>;

    fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
        self.pin_get_inner()
            .poll(cx)
            .map(|result| result.unwrap_or(Err(c_ares::Error::ECANCELLED)))
    }
}

/// An asynchronous DNS resolver, which returns results as `futures::Future`s.
///
/// Note that dropping the `FutureResolver` does *not* cause outstanding queries to fail - contrast
/// the `Resolver` - because the returned futures hold a reference to the underlying resolver.
pub struct FutureResolver {
    inner: Arc<Resolver>,
}

// Most query implementations follow the same pattern: call through to the `Resolver`, arranging
// that the callback completes a future.
macro_rules! futurize {
    ($resolver:expr, $query:ident, $question:expr) => {{
        let (sender, receiver) = futures_channel::oneshot::channel();
        $resolver.$query($question, move |result| {
            let _ = sender.send(result);
        });
        let resolver = Arc::clone(&$resolver);
        CAresFuture::new(receiver, resolver)
    }};
}

impl FutureResolver {
    /// Create a new `FutureResolver`, using default `Options`.
    pub fn new() -> Result<Self, Error> {
        let options = Options::default();
        Self::with_options(options)
    }

    /// Create a new `FutureResolver`, with the given `Options`.
    pub fn with_options(options: Options) -> Result<Self, Error> {
        let inner = Resolver::with_options(options)?;
        let resolver = Self {
            inner: Arc::new(inner),
        };
        Ok(resolver)
    }

    /// Set the list of servers to contact, instead of the servers specified in resolv.conf or the
    /// local named.
    ///
    /// String format is `host[:port]`.  IPv6 addresses with ports require square brackets eg
    /// `[2001:4860:4860::8888]:53`.
    pub fn set_servers(&self, servers: &[&str]) -> c_ares::Result<&Self> {
        self.inner.set_servers(servers)?;
        Ok(self)
    }

    /// Set the local IPv4 address from which to make queries.
    pub fn set_local_ipv4(&self, ipv4: Ipv4Addr) -> &Self {
        self.inner.set_local_ipv4(ipv4);
        self
    }

    /// Set the local IPv6 address from which to make queries.
    pub fn set_local_ipv6(&self, ipv6: &Ipv6Addr) -> &Self {
        self.inner.set_local_ipv6(ipv6);
        self
    }

    /// Set the local device from which to make queries.
    pub fn set_local_device(&self, device: &str) -> &Self {
        self.inner.set_local_device(device);
        self
    }

    /// Initializes an address sortlist configuration, so that addresses returned by
    /// `get_host_by_name()` are sorted according to the sortlist.
    ///
    /// Each element of the sortlist holds an IP-address/netmask pair. The netmask is optional but
    /// follows the address after a slash if present. For example: "130.155.160.0/255.255.240.0",
    /// or "130.155.0.0".
    pub fn set_sortlist(&self, sortlist: &[&str]) -> c_ares::Result<&Self> {
        self.inner.set_sortlist(sortlist)?;
        Ok(self)
    }

    /// Look up the A records associated with `name`.
    #[must_use]
    pub fn query_a(&self, name: &str) -> CAresFuture<c_ares::AResults> {
        futurize!(self.inner, query_a, name)
    }

    /// Search for the A records associated with `name`.
    #[must_use]
    pub fn search_a(&self, name: &str) -> CAresFuture<c_ares::AResults> {
        futurize!(self.inner, search_a, name)
    }

    /// Look up the AAAA records associated with `name`.
    #[must_use]
    pub fn query_aaaa(&self, name: &str) -> CAresFuture<c_ares::AAAAResults> {
        futurize!(self.inner, query_aaaa, name)
    }

    /// Search for the AAAA records associated with `name`.
    #[must_use]
    pub fn search_aaaa(&self, name: &str) -> CAresFuture<c_ares::AAAAResults> {
        futurize!(self.inner, search_aaaa, name)
    }

    /// Look up the CAA records associated with `name`.
    #[must_use]
    pub fn query_caa(&self, name: &str) -> CAresFuture<c_ares::CAAResults> {
        futurize!(self.inner, query_caa, name)
    }

    /// Search for the CAA records associated with `name`.
    #[must_use]
    pub fn search_caa(&self, name: &str) -> CAresFuture<c_ares::CAAResults> {
        futurize!(self.inner, search_caa, name)
    }

    /// Look up the CNAME records associated with `name`.
    #[must_use]
    pub fn query_cname(&self, name: &str) -> CAresFuture<c_ares::CNameResults> {
        futurize!(self.inner, query_cname, name)
    }

    /// Search for the CNAME records associated with `name`.
    #[must_use]
    pub fn search_cname(&self, name: &str) -> CAresFuture<c_ares::CNameResults> {
        futurize!(self.inner, search_cname, name)
    }

    /// Look up the MX records associated with `name`.
    #[must_use]
    pub fn query_mx(&self, name: &str) -> CAresFuture<c_ares::MXResults> {
        futurize!(self.inner, query_mx, name)
    }

    /// Search for the MX records associated with `name`.
    #[must_use]
    pub fn search_mx(&self, name: &str) -> CAresFuture<c_ares::MXResults> {
        futurize!(self.inner, search_mx, name)
    }

    /// Look up the NAPTR records associated with `name`.
    #[must_use]
    pub fn query_naptr(&self, name: &str) -> CAresFuture<c_ares::NAPTRResults> {
        futurize!(self.inner, query_naptr, name)
    }

    /// Search for the NAPTR records associated with `name`.
    #[must_use]
    pub fn search_naptr(&self, name: &str) -> CAresFuture<c_ares::NAPTRResults> {
        futurize!(self.inner, search_naptr, name)
    }

    /// Look up the NS records associated with `name`.
    #[must_use]
    pub fn query_ns(&self, name: &str) -> CAresFuture<c_ares::NSResults> {
        futurize!(self.inner, query_ns, name)
    }

    /// Search for the NS records associated with `name`.
    #[must_use]
    pub fn search_ns(&self, name: &str) -> CAresFuture<c_ares::NSResults> {
        futurize!(self.inner, search_ns, name)
    }

    /// Look up the PTR records associated with `name`.
    #[must_use]
    pub fn query_ptr(&self, name: &str) -> CAresFuture<c_ares::PTRResults> {
        futurize!(self.inner, query_ptr, name)
    }

    /// Search for the PTR records associated with `name`.
    #[must_use]
    pub fn search_ptr(&self, name: &str) -> CAresFuture<c_ares::PTRResults> {
        futurize!(self.inner, search_ptr, name)
    }

    /// Look up the SOA records associated with `name`.
    #[must_use]
    pub fn query_soa(&self, name: &str) -> CAresFuture<c_ares::SOAResult> {
        futurize!(self.inner, query_soa, name)
    }

    /// Search for the SOA records associated with `name`.
    #[must_use]
    pub fn search_soa(&self, name: &str) -> CAresFuture<c_ares::SOAResult> {
        futurize!(self.inner, search_soa, name)
    }

    /// Look up the SRV records associated with `name`.
    #[must_use]
    pub fn query_srv(&self, name: &str) -> CAresFuture<c_ares::SRVResults> {
        futurize!(self.inner, query_srv, name)
    }

    /// Search for the SRV records associated with `name`.
    #[must_use]
    pub fn search_srv(&self, name: &str) -> CAresFuture<c_ares::SRVResults> {
        futurize!(self.inner, search_srv, name)
    }

    /// Look up the TXT records associated with `name`.
    #[must_use]
    pub fn query_txt(&self, name: &str) -> CAresFuture<c_ares::TXTResults> {
        futurize!(self.inner, query_txt, name)
    }

    /// Search for the TXT records associated with `name`.
    #[must_use]
    pub fn search_txt(&self, name: &str) -> CAresFuture<c_ares::TXTResults> {
        futurize!(self.inner, search_txt, name)
    }

    /// Look up the URI records associated with `name`.
    #[must_use]
    pub fn query_uri(&self, name: &str) -> CAresFuture<c_ares::URIResults> {
        futurize!(self.inner, query_uri, name)
    }

    /// Search for the URI records associated with `name`.
    #[must_use]
    pub fn search_uri(&self, name: &str) -> CAresFuture<c_ares::URIResults> {
        futurize!(self.inner, search_uri, name)
    }

    /// Perform a host query by address.
    ///
    /// This method is one of the very few places where this library performs strictly more
    /// allocation than the underlying `c-ares` code.  If this is a problem for you, you should
    /// prefer to use the analogous method on the `Resolver`.
    #[must_use]
    pub fn get_host_by_address(&self, address: &IpAddr) -> CAresFuture<HostResults> {
        let (sender, receiver) = futures_channel::oneshot::channel();
        self.inner.get_host_by_address(address, move |result| {
            let _ = sender.send(result.map(Into::into));
        });
        let resolver = Arc::clone(&self.inner);
        CAresFuture::new(receiver, resolver)
    }

    /// Perform a host query by name.
    ///
    /// This method is one of the very few places where this library performs strictly more
    /// allocation than the underlying `c-ares` code.  If this is a problem for you, you should
    /// prefer to use the analogous method on the `Resolver`.
    pub fn get_host_by_name(
        &self,
        name: &str,
        family: c_ares::AddressFamily,
    ) -> CAresFuture<HostResults> {
        let (sender, receiver) = futures_channel::oneshot::channel();
        self.inner.get_host_by_name(name, family, move |result| {
            let _ = sender.send(result.map(Into::into));
        });
        let resolver = Arc::clone(&self.inner);
        CAresFuture::new(receiver, resolver)
    }

    /// Address-to-nodename translation in protocol-independent manner.
    ///
    /// This method is one of the very few places where this library performs strictly more
    /// allocation than the underlying `c-ares` code.  If this is a problem for you, you should
    /// prefer to use the analogous method on the `Resolver`.
    #[must_use]
    pub fn get_name_info<F>(
        &self,
        address: &SocketAddr,
        flags: c_ares::NIFlags,
    ) -> CAresFuture<NameInfoResult> {
        let (sender, receiver) = futures_channel::oneshot::channel();
        self.inner.get_name_info(address, flags, move |result| {
            let _ = sender.send(result.map(Into::into));
        });
        let resolver = Arc::clone(&self.inner);
        CAresFuture::new(receiver, resolver)
    }

    /// Initiate a single-question DNS query for `name`.  The class and type of the query are per
    /// the provided parameters, taking values as defined in `arpa/nameser.h`.
    ///
    /// This method is one of the very few places where this library performs strictly more
    /// allocation than the underlying `c-ares` code.  If this is a problem for you, you should
    /// prefer to use the analogous method on the `Resolver`.
    ///
    /// This method is provided so that users can query DNS types for which `c-ares` does not
    /// provide a parser; or in case a third-party parser is preferred.  Usually, if a suitable
    /// `query_xxx()` is available, that should be used.
    #[must_use]
    pub fn query(&self, name: &str, dns_class: u16, query_type: u16) -> CAresFuture<Vec<u8>> {
        let (sender, receiver) = futures_channel::oneshot::channel();
        self.inner
            .query(name, dns_class, query_type, move |result| {
                let _ = sender.send(result.map(std::borrow::ToOwned::to_owned));
            });
        let resolver = Arc::clone(&self.inner);
        CAresFuture::new(receiver, resolver)
    }

    /// Initiate a series of single-question DNS queries for `name`.  The class and type of the
    /// query are per the provided parameters, taking values as defined in `arpa/nameser.h`.
    ///
    /// This method is one of the very few places where this library performs strictly more
    /// allocation than the underlying `c-ares` code.  If this is a problem for you, you should
    /// prefer to use the analogous method on the `Resolver`.
    ///
    /// This method is provided so that users can search DNS types for which `c-ares` does not
    /// provide a parser; or in case a third-party parser is preferred.  Usually, if a suitable
    /// `search_xxx()` is available, that should be used.
    pub fn search(&self, name: &str, dns_class: u16, query_type: u16) -> CAresFuture<Vec<u8>> {
        let (sender, receiver) = futures_channel::oneshot::channel();
        self.inner
            .search(name, dns_class, query_type, move |result| {
                let _ = sender.send(result.map(std::borrow::ToOwned::to_owned));
            });
        let resolver = Arc::clone(&self.inner);
        CAresFuture::new(receiver, resolver)
    }

    /// Cancel all requests made on this `FutureResolver`.
    pub fn cancel(&self) {
        self.inner.cancel()
    }
}
<commit_msg>simpler must_use<commit_after>use std::future::Future;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
use std::pin::Pin;
use std::sync::Arc;
use std::task::{Context, Poll};

use crate::error::Error;
use crate::host::HostResults;
use crate::nameinfo::NameInfoResult;
use crate::resolver::{Options, Resolver};

/// The type of future returned by methods on the `FutureResolver`.
#[must_use]
pub struct CAresFuture<T> {
    inner: futures_channel::oneshot::Receiver<c_ares::Result<T>>,
    _resolver: Arc<Resolver>,
}

impl<T> CAresFuture<T> {
    fn new(
        promise: futures_channel::oneshot::Receiver<c_ares::Result<T>>,
        resolver: Arc<Resolver>,
    ) -> Self {
        Self {
            inner: promise,
            _resolver: resolver,
        }
    }

    fn pin_get_inner(
        self: Pin<&mut Self>,
    ) -> Pin<&mut futures_channel::oneshot::Receiver<c_ares::Result<T>>> {
        unsafe { self.map_unchecked_mut(|s| &mut s.inner) }
    }
}

impl<T> Future for CAresFuture<T> {
    type Output = c_ares::Result<T>;

    fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
        self.pin_get_inner()
            .poll(cx)
            .map(|result| result.unwrap_or(Err(c_ares::Error::ECANCELLED)))
    }
}

/// An asynchronous DNS resolver, which returns results as `futures::Future`s.
///
/// Note that dropping the `FutureResolver` does *not* cause outstanding queries to fail - contrast
/// the `Resolver` - because the returned futures hold a reference to the underlying resolver.
pub struct FutureResolver {
    inner: Arc<Resolver>,
}

// Most query implementations follow the same pattern: call through to the `Resolver`, arranging
// that the callback completes a future.
macro_rules! futurize {
    ($resolver:expr, $query:ident, $question:expr) => {{
        let (sender, receiver) = futures_channel::oneshot::channel();
        $resolver.$query($question, move |result| {
            let _ = sender.send(result);
        });
        let resolver = Arc::clone(&$resolver);
        CAresFuture::new(receiver, resolver)
    }};
}

impl FutureResolver {
    /// Create a new `FutureResolver`, using default `Options`.
    pub fn new() -> Result<Self, Error> {
        let options = Options::default();
        Self::with_options(options)
    }

    /// Create a new `FutureResolver`, with the given `Options`.
    pub fn with_options(options: Options) -> Result<Self, Error> {
        let inner = Resolver::with_options(options)?;
        let resolver = Self {
            inner: Arc::new(inner),
        };
        Ok(resolver)
    }

    /// Set the list of servers to contact, instead of the servers specified in resolv.conf or the
    /// local named.
    ///
    /// String format is `host[:port]`.  IPv6 addresses with ports require square brackets eg
    /// `[2001:4860:4860::8888]:53`.
    pub fn set_servers(&self, servers: &[&str]) -> c_ares::Result<&Self> {
        self.inner.set_servers(servers)?;
        Ok(self)
    }

    /// Set the local IPv4 address from which to make queries.
    pub fn set_local_ipv4(&self, ipv4: Ipv4Addr) -> &Self {
        self.inner.set_local_ipv4(ipv4);
        self
    }

    /// Set the local IPv6 address from which to make queries.
    pub fn set_local_ipv6(&self, ipv6: &Ipv6Addr) -> &Self {
        self.inner.set_local_ipv6(ipv6);
        self
    }

    /// Set the local device from which to make queries.
    pub fn set_local_device(&self, device: &str) -> &Self {
        self.inner.set_local_device(device);
        self
    }

    /// Initializes an address sortlist configuration, so that addresses returned by
    /// `get_host_by_name()` are sorted according to the sortlist.
    ///
    /// Each element of the sortlist holds an IP-address/netmask pair. The netmask is optional but
    /// follows the address after a slash if present. For example: "130.155.160.0/255.255.240.0",
    /// or "130.155.0.0".
    pub fn set_sortlist(&self, sortlist: &[&str]) -> c_ares::Result<&Self> {
        self.inner.set_sortlist(sortlist)?;
        Ok(self)
    }

    /// Look up the A records associated with `name`.
    pub fn query_a(&self, name: &str) -> CAresFuture<c_ares::AResults> {
        futurize!(self.inner, query_a, name)
    }

    /// Search for the A records associated with `name`.
    pub fn search_a(&self, name: &str) -> CAresFuture<c_ares::AResults> {
        futurize!(self.inner, search_a, name)
    }

    /// Look up the AAAA records associated with `name`.
    pub fn query_aaaa(&self, name: &str) -> CAresFuture<c_ares::AAAAResults> {
        futurize!(self.inner, query_aaaa, name)
    }

    /// Search for the AAAA records associated with `name`.
    pub fn search_aaaa(&self, name: &str) -> CAresFuture<c_ares::AAAAResults> {
        futurize!(self.inner, search_aaaa, name)
    }

    /// Look up the CAA records associated with `name`.
    pub fn query_caa(&self, name: &str) -> CAresFuture<c_ares::CAAResults> {
        futurize!(self.inner, query_caa, name)
    }

    /// Search for the CAA records associated with `name`.
    pub fn search_caa(&self, name: &str) -> CAresFuture<c_ares::CAAResults> {
        futurize!(self.inner, search_caa, name)
    }

    /// Look up the CNAME records associated with `name`.
    pub fn query_cname(&self, name: &str) -> CAresFuture<c_ares::CNameResults> {
        futurize!(self.inner, query_cname, name)
    }

    /// Search for the CNAME records associated with `name`.
    pub fn search_cname(&self, name: &str) -> CAresFuture<c_ares::CNameResults> {
        futurize!(self.inner, search_cname, name)
    }

    /// Look up the MX records associated with `name`.
    pub fn query_mx(&self, name: &str) -> CAresFuture<c_ares::MXResults> {
        futurize!(self.inner, query_mx, name)
    }

    /// Search for the MX records associated with `name`.
    pub fn search_mx(&self, name: &str) -> CAresFuture<c_ares::MXResults> {
        futurize!(self.inner, search_mx, name)
    }

    /// Look up the NAPTR records associated with `name`.
    pub fn query_naptr(&self, name: &str) -> CAresFuture<c_ares::NAPTRResults> {
        futurize!(self.inner, query_naptr, name)
    }

    /// Search for the NAPTR records associated with `name`.
    pub fn search_naptr(&self, name: &str) -> CAresFuture<c_ares::NAPTRResults> {
        futurize!(self.inner, search_naptr, name)
    }

    /// Look up the NS records associated with `name`.
    pub fn query_ns(&self, name: &str) -> CAresFuture<c_ares::NSResults> {
        futurize!(self.inner, query_ns, name)
    }

    /// Search for the NS records associated with `name`.
    pub fn search_ns(&self, name: &str) -> CAresFuture<c_ares::NSResults> {
        futurize!(self.inner, search_ns, name)
    }

    /// Look up the PTR records associated with `name`.
    pub fn query_ptr(&self, name: &str) -> CAresFuture<c_ares::PTRResults> {
        futurize!(self.inner, query_ptr, name)
    }

    /// Search for the PTR records associated with `name`.
    pub fn search_ptr(&self, name: &str) -> CAresFuture<c_ares::PTRResults> {
        futurize!(self.inner, search_ptr, name)
    }

    /// Look up the SOA records associated with `name`.
    pub fn query_soa(&self, name: &str) -> CAresFuture<c_ares::SOAResult> {
        futurize!(self.inner, query_soa, name)
    }

    /// Search for the SOA records associated with `name`.
    pub fn search_soa(&self, name: &str) -> CAresFuture<c_ares::SOAResult> {
        futurize!(self.inner, search_soa, name)
    }

    /// Look up the SRV records associated with `name`.
    pub fn query_srv(&self, name: &str) -> CAresFuture<c_ares::SRVResults> {
        futurize!(self.inner, query_srv, name)
    }

    /// Search for the SRV records associated with `name`.
    pub fn search_srv(&self, name: &str) -> CAresFuture<c_ares::SRVResults> {
        futurize!(self.inner, search_srv, name)
    }

    /// Look up the TXT records associated with `name`.
    pub fn query_txt(&self, name: &str) -> CAresFuture<c_ares::TXTResults> {
        futurize!(self.inner, query_txt, name)
    }

    /// Search for the TXT records associated with `name`.
    pub fn search_txt(&self, name: &str) -> CAresFuture<c_ares::TXTResults> {
        futurize!(self.inner, search_txt, name)
    }

    /// Look up the URI records associated with `name`.
    pub fn query_uri(&self, name: &str) -> CAresFuture<c_ares::URIResults> {
        futurize!(self.inner, query_uri, name)
    }

    /// Search for the URI records associated with `name`.
    pub fn search_uri(&self, name: &str) -> CAresFuture<c_ares::URIResults> {
        futurize!(self.inner, search_uri, name)
    }

    /// Perform a host query by address.
    ///
    /// This method is one of the very few places where this library performs strictly more
    /// allocation than the underlying `c-ares` code.  If this is a problem for you, you should
    /// prefer to use the analogous method on the `Resolver`.
    pub fn get_host_by_address(&self, address: &IpAddr) -> CAresFuture<HostResults> {
        let (sender, receiver) = futures_channel::oneshot::channel();
        self.inner.get_host_by_address(address, move |result| {
            let _ = sender.send(result.map(Into::into));
        });
        let resolver = Arc::clone(&self.inner);
        CAresFuture::new(receiver, resolver)
    }

    /// Perform a host query by name.
    ///
    /// This method is one of the very few places where this library performs strictly more
    /// allocation than the underlying `c-ares` code.  If this is a problem for you, you should
    /// prefer to use the analogous method on the `Resolver`.
    pub fn get_host_by_name(
        &self,
        name: &str,
        family: c_ares::AddressFamily,
    ) -> CAresFuture<HostResults> {
        let (sender, receiver) = futures_channel::oneshot::channel();
        self.inner.get_host_by_name(name, family, move |result| {
            let _ = sender.send(result.map(Into::into));
        });
        let resolver = Arc::clone(&self.inner);
        CAresFuture::new(receiver, resolver)
    }

    /// Address-to-nodename translation in protocol-independent manner.
    ///
    /// This method is one of the very few places where this library performs strictly more
    /// allocation than the underlying `c-ares` code.  If this is a problem for you, you should
    /// prefer to use the analogous method on the `Resolver`.
    pub fn get_name_info<F>(
        &self,
        address: &SocketAddr,
        flags: c_ares::NIFlags,
    ) -> CAresFuture<NameInfoResult> {
        let (sender, receiver) = futures_channel::oneshot::channel();
        self.inner.get_name_info(address, flags, move |result| {
            let _ = sender.send(result.map(Into::into));
        });
        let resolver = Arc::clone(&self.inner);
        CAresFuture::new(receiver, resolver)
    }

    /// Initiate a single-question DNS query for `name`.  The class and type of the query are per
    /// the provided parameters, taking values as defined in `arpa/nameser.h`.
    ///
    /// This method is one of the very few places where this library performs strictly more
    /// allocation than the underlying `c-ares` code.  If this is a problem for you, you should
    /// prefer to use the analogous method on the `Resolver`.
    ///
    /// This method is provided so that users can query DNS types for which `c-ares` does not
    /// provide a parser; or in case a third-party parser is preferred.  Usually, if a suitable
    /// `query_xxx()` is available, that should be used.
    pub fn query(&self, name: &str, dns_class: u16, query_type: u16) -> CAresFuture<Vec<u8>> {
        let (sender, receiver) = futures_channel::oneshot::channel();
        self.inner
            .query(name, dns_class, query_type, move |result| {
                let _ = sender.send(result.map(std::borrow::ToOwned::to_owned));
            });
        let resolver = Arc::clone(&self.inner);
        CAresFuture::new(receiver, resolver)
    }

    /// Initiate a series of single-question DNS queries for `name`.  The class and type of the
    /// query are per the provided parameters, taking values as defined in `arpa/nameser.h`.
    ///
    /// This method is one of the very few places where this library performs strictly more
    /// allocation than the underlying `c-ares` code.  If this is a problem for you, you should
    /// prefer to use the analogous method on the `Resolver`.
    ///
    /// This method is provided so that users can search DNS types for which `c-ares` does not
    /// provide a parser; or in case a third-party parser is preferred.  Usually, if a suitable
    /// `search_xxx()` is available, that should be used.
    pub fn search(&self, name: &str, dns_class: u16, query_type: u16) -> CAresFuture<Vec<u8>> {
        let (sender, receiver) = futures_channel::oneshot::channel();
        self.inner
            .search(name, dns_class, query_type, move |result| {
                let _ = sender.send(result.map(std::borrow::ToOwned::to_owned));
            });
        let resolver = Arc::clone(&self.inner);
        CAresFuture::new(receiver, resolver)
    }

    /// Cancel all requests made on this `FutureResolver`.
    pub fn cancel(&self) {
        self.inner.cancel()
    }
}
<|endoftext|>


<commit_before>// Copyright 2022 The ChromiumOS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::io::Read;
use std::io::{self};
use std::os::unix::net::UnixStream;

use libc::c_void;
use libc::{self};

use super::super::net::UnixSeqpacket;
use super::super::Result;
use super::RawDescriptor;
use crate::descriptor::AsRawDescriptor;
use crate::ReadNotifier;

#[derive(Copy, Clone)]
pub enum FramingMode {
    Message,
    Byte,
}

#[derive(Copy, Clone, PartialEq, Eq)]
pub enum BlockingMode {
    Blocking,
    Nonblocking,
}

impl io::Read for StreamChannel {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.inner_read(buf)
    }
}

impl io::Read for &StreamChannel {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.inner_read(buf)
    }
}

impl AsRawDescriptor for StreamChannel {
    fn as_raw_descriptor(&self) -> RawDescriptor {
        (&self).as_raw_descriptor()
    }
}

enum SocketType {
    Message(UnixSeqpacket),
    Byte(UnixStream),
}

/// An abstraction over named pipes and unix socketpairs. This abstraction can be used in a blocking
/// and non blocking mode.
pub struct StreamChannel {
    stream: SocketType,
}

impl StreamChannel {
    pub fn set_nonblocking(&mut self, nonblocking: bool) -> io::Result<()> {
        match &mut self.stream {
            SocketType::Byte(sock) => sock.set_nonblocking(nonblocking),
            SocketType::Message(sock) => sock.set_nonblocking(nonblocking),
        }
    }

    pub(super) fn inner_read(&self, buf: &mut [u8]) -> io::Result<usize> {
        match &self.stream {
            SocketType::Byte(sock) => (&mut &*sock).read(buf),

            // On Windows, reading from SOCK_SEQPACKET with a buffer that is too small is an error,
            // but on Linux will silently truncate unless MSG_TRUNC is passed. Here, we emulate
            // Windows behavior on POSIX.
            //
            // Note that Rust translates ERROR_MORE_DATA into io::ErrorKind::Other
            // (see sys::decode_error_kind) on Windows, so we preserve this behavior on POSIX even
            // though one could argue ErrorKind::UnexpectedEof is a closer match to the true error.
            SocketType::Message(sock) => {
                // Safe because buf is valid, we pass buf's size to recv to bound the return
                // length, and we check the return code.
                let retval = unsafe {
                    // TODO(nkgold|b/152067913): Move this into the UnixSeqpacket struct as a
                    // recv_with_flags method once that struct's tests are working.
                    libc::recv(
                        sock.as_raw_descriptor(),
                        buf.as_mut_ptr() as *mut c_void,
                        buf.len(),
                        libc::MSG_TRUNC,
                    )
                };
                let receive_len = if retval < 0 {
                    Err(std::io::Error::last_os_error())
                } else {
                    Ok(retval)
                }? as usize;

                if receive_len > buf.len() {
                    Err(std::io::Error::new(
                        std::io::ErrorKind::Other,
                        format!(
                            "packet size {:?} encountered, but buffer was only of size {:?}",
                            receive_len,
                            buf.len()
                        ),
                    ))
                } else {
                    Ok(receive_len)
                }
            }
        }
    }

    /// Creates a cross platform stream pair.
    pub fn pair(
        blocking_mode: BlockingMode,
        framing_mode: FramingMode,
    ) -> Result<(StreamChannel, StreamChannel)> {
        let (pipe_a, pipe_b) = match framing_mode {
            FramingMode::Byte => {
                let (pipe_a, pipe_b) = UnixStream::pair()?;
                (SocketType::Byte(pipe_a), SocketType::Byte(pipe_b))
            }
            FramingMode::Message => {
                let (pipe_a, pipe_b) = UnixSeqpacket::pair()?;
                (SocketType::Message(pipe_a), SocketType::Message(pipe_b))
            }
        };
        let mut stream_a = StreamChannel { stream: pipe_a };
        let mut stream_b = StreamChannel { stream: pipe_b };
        let is_non_blocking = blocking_mode == BlockingMode::Nonblocking;
        stream_a.set_nonblocking(is_non_blocking)?;
        stream_b.set_nonblocking(is_non_blocking)?;
        Ok((stream_a, stream_b))
    }
}

impl io::Write for StreamChannel {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        match &mut self.stream {
            SocketType::Byte(sock) => sock.write(buf),
            SocketType::Message(sock) => sock.send(buf),
        }
    }
    fn flush(&mut self) -> io::Result<()> {
        match &mut self.stream {
            SocketType::Byte(sock) => sock.flush(),
            SocketType::Message(_) => Ok(()),
        }
    }
}

impl AsRawDescriptor for &StreamChannel {
    fn as_raw_descriptor(&self) -> RawDescriptor {
        match &self.stream {
            SocketType::Byte(sock) => sock.as_raw_descriptor(),
            SocketType::Message(sock) => sock.as_raw_descriptor(),
        }
    }
}

impl ReadNotifier for StreamChannel {
    /// Returns a RawDescriptor that can be polled for reads using PollContext.
    fn get_read_notifier(&self) -> &dyn AsRawDescriptor {
        self
    }
}

#[cfg(test)]
mod test {
    use std::io::Read;
    use std::io::Write;

    use super::*;
    use crate::EventContext;
    use crate::EventToken;
    use crate::ReadNotifier;

    #[derive(EventToken, Debug, Eq, PartialEq, Copy, Clone)]
    enum Token {
        ReceivedData,
    }

    #[test]
    fn test_non_blocking_pair() {
        let (mut sender, mut receiver) =
            StreamChannel::pair(BlockingMode::Nonblocking, FramingMode::Byte).unwrap();

        sender.write_all(&[75, 77, 54, 82, 76, 65]).unwrap();

        // Wait for the data to arrive.
        let event_ctx: EventContext<Token> =
            EventContext::build_with(&[(receiver.get_read_notifier(), Token::ReceivedData)])
                .unwrap();
        let events = event_ctx.wait().unwrap();
        let tokens: Vec<Token> = events
            .iter()
            .filter(|e| e.is_readable)
            .map(|e| e.token)
            .collect();
        assert_eq!(tokens, vec! {Token::ReceivedData});

        // Smaller than what we sent so we get multiple chunks
        let mut recv_buffer: [u8; 4] = [0; 4];

        let mut size = receiver.read(&mut recv_buffer).unwrap();
        assert_eq!(size, 4);
        assert_eq!(recv_buffer, [75, 77, 54, 82]);

        size = receiver.read(&mut recv_buffer).unwrap();
        assert_eq!(size, 2);
        assert_eq!(recv_buffer[0..2], [76, 65]);

        // Now that we've polled for & received all data, polling again should show no events.
        assert_eq!(
            event_ctx
                .wait_timeout(std::time::Duration::new(0, 0))
                .unwrap()
                .len(),
            0
        );
    }

    #[test]
    fn test_non_blocking_pair_error_no_data() {
        let (mut sender, mut receiver) =
            StreamChannel::pair(BlockingMode::Nonblocking, FramingMode::Byte).unwrap();
        receiver
            .set_nonblocking(true)
            .expect("Failed to set receiver to nonblocking mode.");

        sender.write_all(&[75, 77]).unwrap();

        // Wait for the data to arrive.
        let event_ctx: EventContext<Token> =
            EventContext::build_with(&[(receiver.get_read_notifier(), Token::ReceivedData)])
                .unwrap();
        let events = event_ctx.wait().unwrap();
        let tokens: Vec<Token> = events
            .iter()
            .filter(|e| e.is_readable)
            .map(|e| e.token)
            .collect();
        assert_eq!(tokens, vec! {Token::ReceivedData});

        // We only read 2 bytes, even though we requested 4 bytes.
        let mut recv_buffer: [u8; 4] = [0; 4];
        let size = receiver.read(&mut recv_buffer).unwrap();
        assert_eq!(size, 2);
        assert_eq!(recv_buffer, [75, 77, 00, 00]);

        // Further reads should encounter an error since there is no available data and this is a
        // non blocking pipe.
        assert!(receiver.read(&mut recv_buffer).is_err());
    }
}
<commit_msg>base/src: Add Unix StreamChannel Message test<commit_after>// Copyright 2022 The ChromiumOS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::io::Read;
use std::io::{self};
use std::os::unix::net::UnixStream;

use libc::c_void;
use libc::{self};

use super::super::net::UnixSeqpacket;
use super::super::Result;
use super::RawDescriptor;
use crate::descriptor::AsRawDescriptor;
use crate::ReadNotifier;

#[derive(Copy, Clone)]
pub enum FramingMode {
    Message,
    Byte,
}

#[derive(Copy, Clone, PartialEq, Eq)]
pub enum BlockingMode {
    Blocking,
    Nonblocking,
}

impl io::Read for StreamChannel {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.inner_read(buf)
    }
}

impl io::Read for &StreamChannel {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.inner_read(buf)
    }
}

impl AsRawDescriptor for StreamChannel {
    fn as_raw_descriptor(&self) -> RawDescriptor {
        (&self).as_raw_descriptor()
    }
}

enum SocketType {
    Message(UnixSeqpacket),
    Byte(UnixStream),
}

/// An abstraction over named pipes and unix socketpairs. This abstraction can be used in a blocking
/// and non blocking mode.
pub struct StreamChannel {
    stream: SocketType,
}

impl StreamChannel {
    pub fn set_nonblocking(&mut self, nonblocking: bool) -> io::Result<()> {
        match &mut self.stream {
            SocketType::Byte(sock) => sock.set_nonblocking(nonblocking),
            SocketType::Message(sock) => sock.set_nonblocking(nonblocking),
        }
    }

    pub(super) fn inner_read(&self, buf: &mut [u8]) -> io::Result<usize> {
        match &self.stream {
            SocketType::Byte(sock) => (&mut &*sock).read(buf),

            // On Windows, reading from SOCK_SEQPACKET with a buffer that is too small is an error,
            // but on Linux will silently truncate unless MSG_TRUNC is passed. Here, we emulate
            // Windows behavior on POSIX.
            //
            // Note that Rust translates ERROR_MORE_DATA into io::ErrorKind::Other
            // (see sys::decode_error_kind) on Windows, so we preserve this behavior on POSIX even
            // though one could argue ErrorKind::UnexpectedEof is a closer match to the true error.
            SocketType::Message(sock) => {
                // Safe because buf is valid, we pass buf's size to recv to bound the return
                // length, and we check the return code.
                let retval = unsafe {
                    // TODO(nkgold|b/152067913): Move this into the UnixSeqpacket struct as a
                    // recv_with_flags method once that struct's tests are working.
                    libc::recv(
                        sock.as_raw_descriptor(),
                        buf.as_mut_ptr() as *mut c_void,
                        buf.len(),
                        libc::MSG_TRUNC,
                    )
                };
                let receive_len = if retval < 0 {
                    Err(std::io::Error::last_os_error())
                } else {
                    Ok(retval)
                }? as usize;

                if receive_len > buf.len() {
                    Err(std::io::Error::new(
                        std::io::ErrorKind::Other,
                        format!(
                            "packet size {:?} encountered, but buffer was only of size {:?}",
                            receive_len,
                            buf.len()
                        ),
                    ))
                } else {
                    Ok(receive_len)
                }
            }
        }
    }

    /// Creates a cross platform stream pair.
    pub fn pair(
        blocking_mode: BlockingMode,
        framing_mode: FramingMode,
    ) -> Result<(StreamChannel, StreamChannel)> {
        let (pipe_a, pipe_b) = match framing_mode {
            FramingMode::Byte => {
                let (pipe_a, pipe_b) = UnixStream::pair()?;
                (SocketType::Byte(pipe_a), SocketType::Byte(pipe_b))
            }
            FramingMode::Message => {
                let (pipe_a, pipe_b) = UnixSeqpacket::pair()?;
                (SocketType::Message(pipe_a), SocketType::Message(pipe_b))
            }
        };
        let mut stream_a = StreamChannel { stream: pipe_a };
        let mut stream_b = StreamChannel { stream: pipe_b };
        let is_non_blocking = blocking_mode == BlockingMode::Nonblocking;
        stream_a.set_nonblocking(is_non_blocking)?;
        stream_b.set_nonblocking(is_non_blocking)?;
        Ok((stream_a, stream_b))
    }
}

impl io::Write for StreamChannel {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        match &mut self.stream {
            SocketType::Byte(sock) => sock.write(buf),
            SocketType::Message(sock) => sock.send(buf),
        }
    }
    fn flush(&mut self) -> io::Result<()> {
        match &mut self.stream {
            SocketType::Byte(sock) => sock.flush(),
            SocketType::Message(_) => Ok(()),
        }
    }
}

impl AsRawDescriptor for &StreamChannel {
    fn as_raw_descriptor(&self) -> RawDescriptor {
        match &self.stream {
            SocketType::Byte(sock) => sock.as_raw_descriptor(),
            SocketType::Message(sock) => sock.as_raw_descriptor(),
        }
    }
}

impl ReadNotifier for StreamChannel {
    /// Returns a RawDescriptor that can be polled for reads using PollContext.
    fn get_read_notifier(&self) -> &dyn AsRawDescriptor {
        self
    }
}

#[cfg(test)]
mod test {
    use std::io::Read;
    use std::io::Write;

    use super::*;
    use crate::EventContext;
    use crate::EventToken;
    use crate::ReadNotifier;

    #[derive(EventToken, Debug, Eq, PartialEq, Copy, Clone)]
    enum Token {
        ReceivedData,
    }

    #[test]
    fn test_non_blocking_pair_byte() {
        let (mut sender, mut receiver) =
            StreamChannel::pair(BlockingMode::Nonblocking, FramingMode::Byte).unwrap();

        sender.write_all(&[75, 77, 54, 82, 76, 65]).unwrap();

        // Wait for the data to arrive.
        let event_ctx: EventContext<Token> =
            EventContext::build_with(&[(receiver.get_read_notifier(), Token::ReceivedData)])
                .unwrap();
        let events = event_ctx.wait().unwrap();
        let tokens: Vec<Token> = events
            .iter()
            .filter(|e| e.is_readable)
            .map(|e| e.token)
            .collect();
        assert_eq!(tokens, vec! {Token::ReceivedData});

        // Smaller than what we sent so we get multiple chunks
        let mut recv_buffer: [u8; 4] = [0; 4];

        let mut size = receiver.read(&mut recv_buffer).unwrap();
        assert_eq!(size, 4);
        assert_eq!(recv_buffer, [75, 77, 54, 82]);

        size = receiver.read(&mut recv_buffer).unwrap();
        assert_eq!(size, 2);
        assert_eq!(recv_buffer[0..2], [76, 65]);

        // Now that we've polled for & received all data, polling again should show no events.
        assert_eq!(
            event_ctx
                .wait_timeout(std::time::Duration::new(0, 0))
                .unwrap()
                .len(),
            0
        );
    }

    #[test]
    fn test_non_blocking_pair_message() {
        let (mut sender, mut receiver) =
            StreamChannel::pair(BlockingMode::Nonblocking, FramingMode::Message).unwrap();

        sender.write_all(&[75, 77, 54, 82, 76, 65]).unwrap();

        // Wait for the data to arrive.
        let event_ctx: EventContext<Token> =
            EventContext::build_with(&[(receiver.get_read_notifier(), Token::ReceivedData)])
                .unwrap();
        let events = event_ctx.wait().unwrap();
        let tokens: Vec<Token> = events
            .iter()
            .filter(|e| e.is_readable)
            .map(|e| e.token)
            .collect();
        assert_eq!(tokens, vec! {Token::ReceivedData});

        // Unlike Byte format, Message mode panics if the buffer is smaller than the packet size;
        // make the buffer the right size.
        let mut recv_buffer: [u8; 6] = [0; 6];

        let size = receiver.read(&mut recv_buffer).unwrap();
        assert_eq!(size, 6);
        assert_eq!(recv_buffer, [75, 77, 54, 82, 76, 65]);

        // Now that we've polled for & received all data, polling again should show no events.
        assert_eq!(
            event_ctx
                .wait_timeout(std::time::Duration::new(0, 0))
                .unwrap()
                .len(),
            0
        );
    }

    #[test]
    fn test_non_blocking_pair_error_no_data() {
        let (mut sender, mut receiver) =
            StreamChannel::pair(BlockingMode::Nonblocking, FramingMode::Byte).unwrap();
        receiver
            .set_nonblocking(true)
            .expect("Failed to set receiver to nonblocking mode.");

        sender.write_all(&[75, 77]).unwrap();

        // Wait for the data to arrive.
        let event_ctx: EventContext<Token> =
            EventContext::build_with(&[(receiver.get_read_notifier(), Token::ReceivedData)])
                .unwrap();
        let events = event_ctx.wait().unwrap();
        let tokens: Vec<Token> = events
            .iter()
            .filter(|e| e.is_readable)
            .map(|e| e.token)
            .collect();
        assert_eq!(tokens, vec! {Token::ReceivedData});

        // We only read 2 bytes, even though we requested 4 bytes.
        let mut recv_buffer: [u8; 4] = [0; 4];
        let size = receiver.read(&mut recv_buffer).unwrap();
        assert_eq!(size, 2);
        assert_eq!(recv_buffer, [75, 77, 00, 00]);

        // Further reads should encounter an error since there is no available data and this is a
        // non blocking pipe.
        assert!(receiver.read(&mut recv_buffer).is_err());
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::io::Read;
use std::io::prelude;
use std::str;
use nom::*;
use std::fs::{OpenOptions, File};

#[derive(Debug)]
pub struct Cpuinfo<'a> {
    pub field: Option<&'a str>,
    pub value: Option<&'a str>,
}

impl<'a> Cpuinfo<'a> {
    fn new() -> Cpuinfo<'a> {
        Cpuinfo {
            field: None,
            value: None,
        }
    }

    pub fn read_cpuinfo() {
        let mut input = OpenOptions::new().read(true).open("/proc/cpuinfo").unwrap();
        let mut rtv = Vec::new();
        input.read_to_end(&mut rtv);
        match Cpuinfo::parse_cpuinfo(rtv.as_slice()) {
            IResult::Done(a,o) => {
                for o in o {
                    println!("{:?}", o);
                }
            }
            _                  => panic!("Error")
        }
    }

    fn parse_cpuinfo(input:&[u8]) -> IResult<&[u8],Vec<Cpuinfo>> {
        many0!(input,
               chain!(
                   field: map_res!(take_until_either!("\t"), str::from_utf8) ~
                   value: map_res!(take_until_either!("\n"), str::from_utf8) ~ line_ending,
                   ||{
                       Cpuinfo {
                           field: Some(field),
                           value: Some(value)
                       }
                   }
                )
            )
    }

}
<commit_msg>Update cpuinfo.rs<commit_after>use std::io;
use std::io::Read;
use std::io::prelude;
use std::str;
use nom::*;
use std::fs::{OpenOptions, File};

#[derive(Debug)]
pub struct Cpuinfo<'a> {
    pub field: Option<&'a str>,
    pub value: Option<&'a str>,
}

impl<'a> Cpuinfo<'a> {
    fn new() -> Cpuinfo<'a> {
        Cpuinfo {
            field: None,
            value: None,
        }
    }

    pub fn read_cpuinfo() {
        let mut input = OpenOptions::new().read(true).open("/proc/cpuinfo").unwrap();
        let mut rtv = Vec::new();
        input.read_to_end(&mut rtv);
        match Cpuinfo::parse_cpuinfo(rtv.as_slice()) {
            IResult::Done(a,o) => {
                for o in o {
                    println!("{:?}", o);
                }
            }
            _                  => panic!("Error")
        }
    }

    fn parse_cpuinfo(input:&[u8]) -> IResult<&[u8],Vec<Cpuinfo>> {
        many0!(input,
               chain!(
                   field: map_res!(take_until_either!("\t"), str::from_utf8) ~
                   take_until_and_consume!(": ") ~
                   value: map_res!( not_line_ending , str::from_utf8) ~ line_ending,
                   ||{
                       Cpuinfo {
                           field: Some(field),
                           value: Some(value)
                       }
                   }
                )
            )
    }

}
<|endoftext|>