<commit_before>use std::io::{Read, Write};

use crate::{CodePair, DxfError, DxfResult, Point, Vector};

use crate::code_pair_put_back::CodePairPutBack;
use crate::code_pair_writer::CodePairWriter;
use crate::enums::AcadVersion;
use crate::helper_functions::*;

pub(crate) const XDATA_APPLICATIONNAME: i32 = 1001;
const XDATA_STRING: i32 = 1000;
const XDATA_CONTROLGROUP: i32 = 1002;
const XDATA_LAYER: i32 = 1003;
const XDATA_BINARYDATA: i32 = 1004;
const XDATA_HANDLE: i32 = 1005;
const XDATA_THREEREALS: i32 = 1010;
const XDATA_WORLDSPACEPOSITION: i32 = 1011;
const XDATA_WORLDSPACEDISPLACEMENT: i32 = 1012;
const XDATA_WORLDDIRECTION: i32 = 1013;
const XDATA_REAL: i32 = 1040;
const XDATA_DISTANCE: i32 = 1041;
const XDATA_SCALEFACTOR: i32 = 1042;
const XDATA_INTEGER: i32 = 1070;
const XDATA_LONG: i32 = 1071;

/// Represents an application name and a collection of extended data.
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub struct XData {
    pub application_name: String,
    pub items: Vec<XDataItem>,
}

/// Represents a piece of extended data.
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub enum XDataItem {
    Str(String),
    ControlGroup(Vec<XDataItem>),
    LayerName(String),
    BinaryData(Vec<u8>),
    Handle(u32),
    ThreeReals(f64, f64, f64),
    WorldSpacePosition(Point),
    WorldSpaceDisplacement(Point),
    WorldDirection(Vector),
    Real(f64),
    Distance(f64),
    ScaleFactor(f64),
    Integer(i16),
    Long(i32),
}

impl XData {
    pub(crate) fn read_item<I>(
        application_name: String,
        iter: &mut CodePairPutBack<I>,
    ) -> DxfResult<XData>
    where
        I: Read,
    {
        let mut xdata = XData {
            application_name,
            items: vec![],
        };
        loop {
            let pair = match iter.next() {
                Some(Ok(pair @ CodePair { code: 0, .. })) => {
                    iter.put_back(Ok(pair));
                    return Ok(xdata);
                }
                Some(Ok(pair)) => pair,
                Some(Err(e)) => return Err(e),
                None => return Ok(xdata),
            };
            if pair.code == XDATA_APPLICATIONNAME || pair.code < XDATA_STRING {
                // new xdata or non xdata
                break;
            }
            xdata.items.push(XDataItem::read_item(&pair, iter)?);
        }
        Ok(xdata)
    }
    pub(crate) fn write<T>(
        &self,
        version: AcadVersion,
        writer: &mut CodePairWriter<T>,
    ) -> DxfResult<()>
    where
        T: Write + ?Sized,
    {
        // not supported on < R2000
        if version >= AcadVersion::R2000 {
            writer.write_code_pair(&CodePair::new_string(
                XDATA_APPLICATIONNAME,
                &self.application_name,
            ))?;
            for item in &self.items {
                item.write(writer)?;
            }
        }
        Ok(())
    }
}

impl XDataItem {
    fn read_item<I>(pair: &CodePair, iter: &mut CodePairPutBack<I>) -> DxfResult<XDataItem>
    where
        I: Read,
    {
        match pair.code {
            XDATA_STRING => Ok(XDataItem::Str(pair.assert_string()?)),
            XDATA_CONTROLGROUP => {
                let mut items = vec![];
                loop {
                    let pair = match iter.next() {
                        Some(Ok(pair)) => {
                            if pair.code < XDATA_STRING {
                                return Err(DxfError::UnexpectedCodePair(
                                    pair,
                                    String::from("expected XDATA item"),
                                ));
                            }
                            pair
                        }
                        Some(Err(e)) => return Err(e),
                        None => return Err(DxfError::UnexpectedEndOfInput),
                    };
                    if pair.code == XDATA_CONTROLGROUP && pair.assert_string()? == "}" {
                        // end of group
                        break;
                    }

                    items.push(XDataItem::read_item(&pair, iter)?);
                }
                Ok(XDataItem::ControlGroup(items))
            }
            XDATA_LAYER => Ok(XDataItem::LayerName(pair.assert_string()?)),
            XDATA_BINARYDATA => {
                let mut data = vec![];
                parse_hex_string(&pair.assert_string()?, &mut data, pair.offset)?;
                Ok(XDataItem::BinaryData(data))
            }
            XDATA_HANDLE => Ok(XDataItem::Handle(pair.as_handle()?)),
            XDATA_THREEREALS => Ok(XDataItem::ThreeReals(
                pair.assert_f64()?,
                XDataItem::read_double(iter, pair.code)?,
                XDataItem::read_double(iter, pair.code)?,
            )),
            XDATA_WORLDSPACEDISPLACEMENT => Ok(XDataItem::WorldSpaceDisplacement(
                XDataItem::read_point(iter, pair.assert_f64()?, pair.code)?,
            )),
            XDATA_WORLDSPACEPOSITION => Ok(XDataItem::WorldSpacePosition(XDataItem::read_point(
                iter,
                pair.assert_f64()?,
                pair.code,
            )?)),
            XDATA_WORLDDIRECTION => Ok(XDataItem::WorldDirection(XDataItem::read_vector(
                iter,
                pair.assert_f64()?,
                pair.code,
            )?)),
            XDATA_REAL => Ok(XDataItem::Real(pair.assert_f64()?)),
            XDATA_DISTANCE => Ok(XDataItem::Distance(pair.assert_f64()?)),
            XDATA_SCALEFACTOR => Ok(XDataItem::ScaleFactor(pair.assert_f64()?)),
            XDATA_INTEGER => Ok(XDataItem::Integer(pair.assert_i16()?)),
            XDATA_LONG => Ok(XDataItem::Long(pair.assert_i32()?)),
            _ => Err(DxfError::UnexpectedCode(pair.code, pair.offset)),
        }
    }
    fn read_double<T>(iter: &mut CodePairPutBack<T>, expected_code: i32) -> DxfResult<f64>
    where
        T: Read,
    {
        match iter.next() {
            Some(Ok(ref pair)) if pair.code == expected_code => Ok(pair.assert_f64()?),
            Some(Ok(pair)) => Err(DxfError::UnexpectedCode(pair.code, pair.offset)),
            Some(Err(e)) => Err(e),
            None => Err(DxfError::UnexpectedEndOfInput),
        }
    }
    fn read_point<I>(
        iter: &mut CodePairPutBack<I>,
        first: f64,
        expected_code: i32,
    ) -> DxfResult<Point>
    where
        I: Read,
    {
        Ok(Point::new(
            first,
            XDataItem::read_double(iter, expected_code)?,
            XDataItem::read_double(iter, expected_code)?,
        ))
    }
    fn read_vector<I>(
        iter: &mut CodePairPutBack<I>,
        first: f64,
        expected_code: i32,
    ) -> DxfResult<Vector>
    where
        I: Read,
    {
        Ok(Vector::new(
            first,
            XDataItem::read_double(iter, expected_code)?,
            XDataItem::read_double(iter, expected_code)?,
        ))
    }
    pub(crate) fn write<T>(&self, writer: &mut CodePairWriter<T>) -> DxfResult<()>
    where
        T: Write + ?Sized,
    {
        match self {
            XDataItem::Str(ref s) => {
                writer.write_code_pair(&CodePair::new_string(XDATA_STRING, s))?;
            }
            XDataItem::ControlGroup(ref items) => {
                writer.write_code_pair(&CodePair::new_str(XDATA_CONTROLGROUP, "{"))?;
                for item in &items[..] {
                    item.write(writer)?;
                }
                writer.write_code_pair(&CodePair::new_str(XDATA_CONTROLGROUP, "}"))?;
            }
            XDataItem::LayerName(ref l) => {
                writer.write_code_pair(&CodePair::new_string(XDATA_LAYER, l))?;
            }
            XDataItem::BinaryData(ref data) => {
                let mut line = String::new();
                for b in data {
                    line.push_str(&format!("{:02X}", b));
                }
                writer.write_code_pair(&CodePair::new_string(XDATA_BINARYDATA, &line))?;
            }
            XDataItem::Handle(h) => {
                writer.write_code_pair(&CodePair::new_string(XDATA_HANDLE, &as_handle(*h)))?;
            }
            XDataItem::ThreeReals(x, y, z) => {
                writer.write_code_pair(&CodePair::new_f64(XDATA_THREEREALS, *x))?;
                writer.write_code_pair(&CodePair::new_f64(XDATA_THREEREALS, *y))?;
                writer.write_code_pair(&CodePair::new_f64(XDATA_THREEREALS, *z))?;
            }
            XDataItem::WorldSpacePosition(ref p) => {
                writer.write_code_pair(&CodePair::new_f64(XDATA_WORLDSPACEPOSITION, p.x))?;
                writer.write_code_pair(&CodePair::new_f64(XDATA_WORLDSPACEPOSITION, p.y))?;
                writer.write_code_pair(&CodePair::new_f64(XDATA_WORLDSPACEPOSITION, p.z))?;
            }
            XDataItem::WorldSpaceDisplacement(ref p) => {
                writer.write_code_pair(&CodePair::new_f64(XDATA_WORLDSPACEDISPLACEMENT, p.x))?;
                writer.write_code_pair(&CodePair::new_f64(XDATA_WORLDSPACEDISPLACEMENT, p.y))?;
                writer.write_code_pair(&CodePair::new_f64(XDATA_WORLDSPACEDISPLACEMENT, p.z))?;
            }
            XDataItem::WorldDirection(ref v) => {
                writer.write_code_pair(&CodePair::new_f64(XDATA_WORLDDIRECTION, v.x))?;
                writer.write_code_pair(&CodePair::new_f64(XDATA_WORLDDIRECTION, v.y))?;
                writer.write_code_pair(&CodePair::new_f64(XDATA_WORLDDIRECTION, v.z))?;
            }
            XDataItem::Real(f) => {
                writer.write_code_pair(&CodePair::new_f64(XDATA_REAL, *f))?;
            }
            XDataItem::Distance(f) => {
                writer.write_code_pair(&CodePair::new_f64(XDATA_DISTANCE, *f))?;
            }
            XDataItem::ScaleFactor(f) => {
                writer.write_code_pair(&CodePair::new_f64(XDATA_SCALEFACTOR, *f))?;
            }
            XDataItem::Integer(i) => {
                writer.write_code_pair(&CodePair::new_i16(XDATA_INTEGER, *i))?;
            }
            XDataItem::Long(i) => {
                writer.write_code_pair(&CodePair::new_i32(XDATA_LONG, *i))?;
            }
        }
        Ok(())
    }
}
<commit_msg>correct XData triple reading/writing<commit_after>use std::io::{Read, Write};

use crate::{CodePair, DxfError, DxfResult, Point, Vector};

use crate::code_pair_put_back::CodePairPutBack;
use crate::code_pair_writer::CodePairWriter;
use crate::enums::AcadVersion;
use crate::helper_functions::*;

pub(crate) const XDATA_APPLICATIONNAME: i32 = 1001;
const XDATA_STRING: i32 = 1000;
const XDATA_CONTROLGROUP: i32 = 1002;
const XDATA_LAYER: i32 = 1003;
const XDATA_BINARYDATA: i32 = 1004;
const XDATA_HANDLE: i32 = 1005;
const XDATA_THREEREALS: i32 = 1010;
const XDATA_WORLDSPACEPOSITION: i32 = 1011;
const XDATA_WORLDSPACEDISPLACEMENT: i32 = 1012;
const XDATA_WORLDDIRECTION: i32 = 1013;
const XDATA_REAL: i32 = 1040;
const XDATA_DISTANCE: i32 = 1041;
const XDATA_SCALEFACTOR: i32 = 1042;
const XDATA_INTEGER: i32 = 1070;
const XDATA_LONG: i32 = 1071;

/// Represents an application name and a collection of extended data.
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub struct XData {
    pub application_name: String,
    pub items: Vec<XDataItem>,
}

/// Represents a piece of extended data.
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub enum XDataItem {
    Str(String),
    ControlGroup(Vec<XDataItem>),
    LayerName(String),
    BinaryData(Vec<u8>),
    Handle(u32),
    ThreeReals(f64, f64, f64),
    WorldSpacePosition(Point),
    WorldSpaceDisplacement(Point),
    WorldDirection(Vector),
    Real(f64),
    Distance(f64),
    ScaleFactor(f64),
    Integer(i16),
    Long(i32),
}

impl XData {
    pub(crate) fn read_item<I>(
        application_name: String,
        iter: &mut CodePairPutBack<I>,
    ) -> DxfResult<XData>
    where
        I: Read,
    {
        let mut xdata = XData {
            application_name,
            items: vec![],
        };
        loop {
            let pair = match iter.next() {
                Some(Ok(pair @ CodePair { code: 0, .. })) => {
                    iter.put_back(Ok(pair));
                    return Ok(xdata);
                }
                Some(Ok(pair)) => pair,
                Some(Err(e)) => return Err(e),
                None => return Ok(xdata),
            };
            if pair.code == XDATA_APPLICATIONNAME || pair.code < XDATA_STRING {
                // new xdata or non xdata
                break;
            }
            xdata.items.push(XDataItem::read_item(&pair, iter)?);
        }
        Ok(xdata)
    }
    pub(crate) fn write<T>(
        &self,
        version: AcadVersion,
        writer: &mut CodePairWriter<T>,
    ) -> DxfResult<()>
    where
        T: Write + ?Sized,
    {
        // not supported on < R2000
        if version >= AcadVersion::R2000 {
            writer.write_code_pair(&CodePair::new_string(
                XDATA_APPLICATIONNAME,
                &self.application_name,
            ))?;
            for item in &self.items {
                item.write(writer)?;
            }
        }
        Ok(())
    }
}

impl XDataItem {
    fn read_item<I>(pair: &CodePair, iter: &mut CodePairPutBack<I>) -> DxfResult<XDataItem>
    where
        I: Read,
    {
        match pair.code {
            XDATA_STRING => Ok(XDataItem::Str(pair.assert_string()?)),
            XDATA_CONTROLGROUP => {
                let mut items = vec![];
                loop {
                    let pair = match iter.next() {
                        Some(Ok(pair)) => {
                            if pair.code < XDATA_STRING {
                                return Err(DxfError::UnexpectedCodePair(
                                    pair,
                                    String::from("expected XDATA item"),
                                ));
                            }
                            pair
                        }
                        Some(Err(e)) => return Err(e),
                        None => return Err(DxfError::UnexpectedEndOfInput),
                    };
                    if pair.code == XDATA_CONTROLGROUP && pair.assert_string()? == "}" {
                        // end of group
                        break;
                    }

                    items.push(XDataItem::read_item(&pair, iter)?);
                }
                Ok(XDataItem::ControlGroup(items))
            }
            XDATA_LAYER => Ok(XDataItem::LayerName(pair.assert_string()?)),
            XDATA_BINARYDATA => {
                let mut data = vec![];
                parse_hex_string(&pair.assert_string()?, &mut data, pair.offset)?;
                Ok(XDataItem::BinaryData(data))
            }
            XDATA_HANDLE => Ok(XDataItem::Handle(pair.as_handle()?)),
            XDATA_THREEREALS => Ok(XDataItem::ThreeReals(
                pair.assert_f64()?,
                XDataItem::read_double(iter, pair.code + 10)?,
                XDataItem::read_double(iter, pair.code + 20)?,
            )),
            XDATA_WORLDSPACEDISPLACEMENT => Ok(XDataItem::WorldSpaceDisplacement(
                XDataItem::read_point(iter, pair.assert_f64()?, pair.code)?,
            )),
            XDATA_WORLDSPACEPOSITION => Ok(XDataItem::WorldSpacePosition(XDataItem::read_point(
                iter,
                pair.assert_f64()?,
                pair.code,
            )?)),
            XDATA_WORLDDIRECTION => Ok(XDataItem::WorldDirection(XDataItem::read_vector(
                iter,
                pair.assert_f64()?,
                pair.code,
            )?)),
            XDATA_REAL => Ok(XDataItem::Real(pair.assert_f64()?)),
            XDATA_DISTANCE => Ok(XDataItem::Distance(pair.assert_f64()?)),
            XDATA_SCALEFACTOR => Ok(XDataItem::ScaleFactor(pair.assert_f64()?)),
            XDATA_INTEGER => Ok(XDataItem::Integer(pair.assert_i16()?)),
            XDATA_LONG => Ok(XDataItem::Long(pair.assert_i32()?)),
            _ => Err(DxfError::UnexpectedCode(pair.code, pair.offset)),
        }
    }
    fn read_double<T>(iter: &mut CodePairPutBack<T>, expected_code: i32) -> DxfResult<f64>
    where
        T: Read,
    {
        match iter.next() {
            Some(Ok(ref pair)) if pair.code == expected_code => Ok(pair.assert_f64()?),
            Some(Ok(pair)) => Err(DxfError::UnexpectedCode(pair.code, pair.offset)),
            Some(Err(e)) => Err(e),
            None => Err(DxfError::UnexpectedEndOfInput),
        }
    }
    fn read_point<I>(
        iter: &mut CodePairPutBack<I>,
        first: f64,
        expected_code: i32,
    ) -> DxfResult<Point>
    where
        I: Read,
    {
        Ok(Point::new(
            first,
            XDataItem::read_double(iter, expected_code + 10)?,
            XDataItem::read_double(iter, expected_code + 20)?,
        ))
    }
    fn read_vector<I>(
        iter: &mut CodePairPutBack<I>,
        first: f64,
        expected_code: i32,
    ) -> DxfResult<Vector>
    where
        I: Read,
    {
        Ok(Vector::new(
            first,
            XDataItem::read_double(iter, expected_code + 10)?,
            XDataItem::read_double(iter, expected_code + 20)?,
        ))
    }
    pub(crate) fn write<T>(&self, writer: &mut CodePairWriter<T>) -> DxfResult<()>
    where
        T: Write + ?Sized,
    {
        match self {
            XDataItem::Str(ref s) => {
                writer.write_code_pair(&CodePair::new_string(XDATA_STRING, s))?;
            }
            XDataItem::ControlGroup(ref items) => {
                writer.write_code_pair(&CodePair::new_str(XDATA_CONTROLGROUP, "{"))?;
                for item in &items[..] {
                    item.write(writer)?;
                }
                writer.write_code_pair(&CodePair::new_str(XDATA_CONTROLGROUP, "}"))?;
            }
            XDataItem::LayerName(ref l) => {
                writer.write_code_pair(&CodePair::new_string(XDATA_LAYER, l))?;
            }
            XDataItem::BinaryData(ref data) => {
                let mut line = String::new();
                for b in data {
                    line.push_str(&format!("{:02X}", b));
                }
                writer.write_code_pair(&CodePair::new_string(XDATA_BINARYDATA, &line))?;
            }
            XDataItem::Handle(h) => {
                writer.write_code_pair(&CodePair::new_string(XDATA_HANDLE, &as_handle(*h)))?;
            }
            XDataItem::ThreeReals(x, y, z) => {
                writer.write_code_pair(&CodePair::new_f64(XDATA_THREEREALS, *x))?;
                writer.write_code_pair(&CodePair::new_f64(XDATA_THREEREALS + 10, *y))?;
                writer.write_code_pair(&CodePair::new_f64(XDATA_THREEREALS + 20, *z))?;
            }
            XDataItem::WorldSpacePosition(ref p) => {
                writer.write_code_pair(&CodePair::new_f64(XDATA_WORLDSPACEPOSITION, p.x))?;
                writer.write_code_pair(&CodePair::new_f64(XDATA_WORLDSPACEPOSITION + 10, p.y))?;
                writer.write_code_pair(&CodePair::new_f64(XDATA_WORLDSPACEPOSITION + 20, p.z))?;
            }
            XDataItem::WorldSpaceDisplacement(ref p) => {
                writer.write_code_pair(&CodePair::new_f64(XDATA_WORLDSPACEDISPLACEMENT, p.x))?;
                writer
                    .write_code_pair(&CodePair::new_f64(XDATA_WORLDSPACEDISPLACEMENT + 10, p.y))?;
                writer
                    .write_code_pair(&CodePair::new_f64(XDATA_WORLDSPACEDISPLACEMENT + 20, p.z))?;
            }
            XDataItem::WorldDirection(ref v) => {
                writer.write_code_pair(&CodePair::new_f64(XDATA_WORLDDIRECTION, v.x))?;
                writer.write_code_pair(&CodePair::new_f64(XDATA_WORLDDIRECTION + 10, v.y))?;
                writer.write_code_pair(&CodePair::new_f64(XDATA_WORLDDIRECTION + 20, v.z))?;
            }
            XDataItem::Real(f) => {
                writer.write_code_pair(&CodePair::new_f64(XDATA_REAL, *f))?;
            }
            XDataItem::Distance(f) => {
                writer.write_code_pair(&CodePair::new_f64(XDATA_DISTANCE, *f))?;
            }
            XDataItem::ScaleFactor(f) => {
                writer.write_code_pair(&CodePair::new_f64(XDATA_SCALEFACTOR, *f))?;
            }
            XDataItem::Integer(i) => {
                writer.write_code_pair(&CodePair::new_i16(XDATA_INTEGER, *i))?;
            }
            XDataItem::Long(i) => {
                writer.write_code_pair(&CodePair::new_i32(XDATA_LONG, *i))?;
            }
        }
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use crate::enums::AcadVersion;
    use crate::helper_functions::tests::*;
    use crate::objects::*;
    use crate::x_data::{XData, XDataItem};
    use crate::{Drawing, Point, Vector};

    fn read_x_data_items(lines: Vec<&str>) -> Vec<XDataItem> {
        let drawing = from_section(
            "OBJECTS",
            vec![
                "0",
                "ACAD_PROXY_OBJECT",
                "1001",
                "TEST_APPLICATION_NAME",
                lines.join("\r\n").as_str(),
            ]
            .join("\r\n")
            .as_str(),
        );
        let objects = drawing.objects().collect::<Vec<_>>();
        assert_eq!(1, objects.len());
        assert_eq!(1, objects[0].common.x_data.len());
        let x_data = objects[0].common.x_data[0].clone();
        assert_eq!("TEST_APPLICATION_NAME", x_data.application_name);
        x_data.items
    }

    fn read_x_data_item(lines: Vec<&str>) -> XDataItem {
        let items = read_x_data_items(lines);
        assert_eq!(1, items.len());
        items[0].clone()
    }

    fn write_x_data_item(item: XDataItem) -> String {
        let mut drawing = Drawing::new();
        drawing.header.version = AcadVersion::R2000;
        drawing.add_object(Object {
            common: ObjectCommon {
                x_data: vec![XData {
                    application_name: String::from("TEST_APPLICATION_NAME"),
                    items: vec![item],
                }],
                ..Default::default()
            },
            specific: ObjectType::AcadProxyObject(AcadProxyObject::default()),
        });
        to_test_string(&drawing)
    }

    #[test]
    fn read_3_reals() {
        let item = read_x_data_item(vec!["1010", "1.0", "1020", "2.0", "1030", "3.0"]);
        match item {
            XDataItem::ThreeReals(x, y, z) => {
                assert_eq!(1.0, x);
                assert_eq!(2.0, y);
                assert_eq!(3.0, z);
            }
            _ => panic!("expected 3 reals"),
        }
    }

    #[test]
    fn read_world_space_position() {
        let item = read_x_data_item(vec!["1011", "1.0", "1021", "2.0", "1031", "3.0"]);
        match item {
            XDataItem::WorldSpacePosition(p) => {
                assert_eq!(1.0, p.x);
                assert_eq!(2.0, p.y);
                assert_eq!(3.0, p.z);
            }
            _ => panic!("expected 3 reals"),
        }
    }

    #[test]
    fn read_world_space_displacement() {
        let item = read_x_data_item(vec!["1012", "1.0", "1022", "2.0", "1032", "3.0"]);
        match item {
            XDataItem::WorldSpaceDisplacement(p) => {
                assert_eq!(1.0, p.x);
                assert_eq!(2.0, p.y);
                assert_eq!(3.0, p.z);
            }
            _ => panic!("expected 3 reals"),
        }
    }

    #[test]
    fn read_world_direction() {
        let item = read_x_data_item(vec!["1013", "1.0", "1023", "2.0", "1033", "3.0"]);
        match item {
            XDataItem::WorldDirection(v) => {
                assert_eq!(1.0, v.x);
                assert_eq!(2.0, v.y);
                assert_eq!(3.0, v.z);
            }
            _ => panic!("expected 3 reals"),
        }
    }

    #[test]
    fn write_3_reals() {
        let actual = write_x_data_item(XDataItem::ThreeReals(1.0, 2.0, 3.0));
        let expected = vec![
            "1001",
            "TEST_APPLICATION_NAME",
            "1010",
            "1.0",
            "1020",
            "2.0",
            "1030",
            "3.0",
            "  0",
            "ENDSEC",
        ]
        .join("\r\n");
        assert!(actual.contains(&expected));
    }

    #[test]
    fn write_world_space_position() {
        let actual = write_x_data_item(XDataItem::WorldSpacePosition(Point::new(1.0, 2.0, 3.0)));
        let expected = vec![
            "1001",
            "TEST_APPLICATION_NAME",
            "1011",
            "1.0",
            "1021",
            "2.0",
            "1031",
            "3.0",
            "  0",
            "ENDSEC",
        ]
        .join("\r\n");
        assert!(actual.contains(&expected));
    }

    #[test]
    fn write_world_space_displacement() {
        let actual =
            write_x_data_item(XDataItem::WorldSpaceDisplacement(Point::new(1.0, 2.0, 3.0)));
        let expected = vec![
            "1001",
            "TEST_APPLICATION_NAME",
            "1012",
            "1.0",
            "1022",
            "2.0",
            "1032",
            "3.0",
            "  0",
            "ENDSEC",
        ]
        .join("\r\n");
        assert!(actual.contains(&expected));
    }

    #[test]
    fn write_world_direction() {
        let actual = write_x_data_item(XDataItem::WorldDirection(Vector::new(1.0, 2.0, 3.0)));
        let expected = vec![
            "1001",
            "TEST_APPLICATION_NAME",
            "1013",
            "1.0",
            "1023",
            "2.0",
            "1033",
            "3.0",
            "  0",
            "ENDSEC",
        ]
        .join("\r\n");
        assert!(actual.contains(&expected));
    }
}
<|endoftext|>


<commit_before>use criterion::*;
use std::hash::{Hash, Hasher};
use std::collections::hash_map::DefaultHasher;
use ahash::*;
use ahash::fallback::{FallbackHasher};
use fxhash::{FxHasher};

#[cfg(all(
any(target_arch = "x86", target_arch = "x86_64"),
target_feature = "aes"
))]
pub fn ahash<H: Hash>(b: H) -> u64 {
    let mut hasher = AHasher::default();
    b.hash(&mut hasher);
    hasher.finish()
}

fn fallbackhash<H: Hash>(b: H) -> u64 {
    let mut hasher = FallbackHasher::default();
    b.hash(&mut hasher);
    hasher.finish()
}

fn fnvhash<H: Hash>(b: H) -> u64 {
    let mut hasher = fnv::FnvHasher::default();
    b.hash(&mut hasher);
    hasher.finish()
}

fn siphash<H: Hash>(b: H) -> u64 {
    let mut hasher = DefaultHasher::default();
    b.hash(&mut hasher);
    hasher.finish()
}

fn fxhash<H: Hash>(b: H) -> u64 {
    let mut hasher = FxHasher::default();
    b.hash(&mut hasher);
    hasher.finish()
}

fn seahash<H: Hash>(b: H) -> u64 {
    let mut hasher = seahash::SeaHasher::default();
    b.hash(&mut hasher);
    hasher.finish()
}

const VALUES: [&str; 5] = ["1",
    "123",
//    "1234",
//    "1234567",
//    "12345678",
//    "123456789012345",
//    "1234567890123456",
    "123456789012345678901234",
    "12345678901234567890123456789012345678901234567890123456789012345678",
    "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012"];

const U8_VALUES: [u32; 1] = [8];
const U16_VALUES: [u16; 1] = [16];
const U32_VALUES: [u32; 1] = [32];
const U64_VALUES: [u64; 1] = [64];
const U128_VALUES: [u128; 1] = [128];

#[cfg(all(
any(target_arch = "x86", target_arch = "x86_64"),
target_feature = "aes"
))]
fn bench_ahash(c: &mut Criterion) {
    c.bench(
        "ahash",
        ParameterizedBenchmark::new("u8", |b, s| b.iter(|| black_box(ahash(&s))), &U8_VALUES),
    );
    c.bench(
        "ahash",
        ParameterizedBenchmark::new("u16", |b, s| b.iter(|| black_box(ahash(&s))), &U16_VALUES),
    );
    c.bench(
        "ahash",
        ParameterizedBenchmark::new("u32", |b, s| b.iter(|| black_box(ahash(&s))), &U32_VALUES),
    );
    c.bench(
        "ahash",
        ParameterizedBenchmark::new("u64", |b, s| b.iter(|| black_box(ahash(&s))), &U64_VALUES),
    );
    c.bench(
        "ahash",
        ParameterizedBenchmark::new("u128", |b, s| b.iter(|| black_box(ahash(&s))), &U128_VALUES),
    );
    c.bench(
        "ahash",
        ParameterizedBenchmark::new("string", |b, s| b.iter(|| black_box(ahash(&s))), &VALUES),
    );
}

fn bench_fallback(c: &mut Criterion) {
//    c.bench(
//        "fallback",
//        ParameterizedBenchmark::new("u8", |b, s| b.iter(|| black_box(fallbackhash(&s))), &U8_VALUES),
//    );
//    c.bench(
//        "fallback",
//        ParameterizedBenchmark::new("u16", |b, s| b.iter(|| black_box(fallbackhash(&s))), &U16_VALUES),
//    );
//    c.bench(
//        "fallback",
//        ParameterizedBenchmark::new("u32", |b, s| b.iter(|| black_box(fallbackhash(&s))), &U32_VALUES),
//    );
//    c.bench(
//        "fallback",
//        ParameterizedBenchmark::new("u64", |b, s| b.iter(|| black_box(fallbackhash(&s))), &U64_VALUES),
//    );
//    c.bench(
//        "fallback",
//        ParameterizedBenchmark::new("u128", |b, s| b.iter(|| black_box(fallbackhash(&s))), &U128_VALUES),
//    );
    c.bench(
        "fallback",
        ParameterizedBenchmark::new("string", |b, s| b.iter(|| black_box(fallbackhash(&s))), &VALUES),
    );
}

fn bench_fx(c: &mut Criterion) {
    c.bench(
        "fx",
        ParameterizedBenchmark::new("u8", |b, s| b.iter(|| black_box(fxhash(&s))), &U8_VALUES),
    );
    c.bench(
        "fx",
        ParameterizedBenchmark::new("u16", |b, s| b.iter(|| black_box(fxhash(&s))), &U16_VALUES),
    );
    c.bench(
        "fx",
        ParameterizedBenchmark::new("u32", |b, s| b.iter(|| black_box(fxhash(&s))), &U32_VALUES),
    );
    c.bench(
        "fx",
        ParameterizedBenchmark::new("u64", |b, s| b.iter(|| black_box(fxhash(&s))), &U64_VALUES),
    );
    c.bench(
        "fx",
        ParameterizedBenchmark::new("u128", |b, s| b.iter(|| black_box(fxhash(&s))), &U128_VALUES),
    );
    c.bench(
        "fx",
        ParameterizedBenchmark::new("string", |b, s| b.iter(|| black_box(fxhash(&s))), &VALUES),
    );
}

fn bench_fnv(c: &mut Criterion) {
    c.bench(
        "fnv",
        ParameterizedBenchmark::new("u8", |b, s| b.iter(|| black_box(fnvhash(&s))), &U8_VALUES),
    );
    c.bench(
        "fnv",
        ParameterizedBenchmark::new("u16", |b, s| b.iter(|| black_box(fnvhash(&s))), &U16_VALUES),
    );
    c.bench(
        "fnv",
        ParameterizedBenchmark::new("u32", |b, s| b.iter(|| black_box(fnvhash(&s))), &U32_VALUES),
    );
    c.bench(
        "fnv",
        ParameterizedBenchmark::new("u64", |b, s| b.iter(|| black_box(fnvhash(&s))), &U64_VALUES),
    );
    c.bench(
        "fnv",
        ParameterizedBenchmark::new("u128", |b, s| b.iter(|| black_box(fnvhash(&s))), &U128_VALUES),
    );
    c.bench(
        "fnv",
        ParameterizedBenchmark::new("string", |b, s| b.iter(|| black_box(fnvhash(&s))), &VALUES),
    );
}

fn bench_sea(c: &mut Criterion) {
    c.bench(
        "sea",
        ParameterizedBenchmark::new("string", |b, s| b.iter(|| black_box(seahash(&s))), &VALUES),
    );
}

fn bench_sip(c: &mut Criterion) {
    c.bench(
        "sip",
        ParameterizedBenchmark::new("u8", |b, s| b.iter(|| black_box(siphash(&s))), &U8_VALUES),
    );
    c.bench(
        "sip",
        ParameterizedBenchmark::new("u16", |b, s| b.iter(|| black_box(siphash(&s))), &U16_VALUES),
    );
    c.bench(
        "sip",
        ParameterizedBenchmark::new("u32", |b, s| b.iter(|| black_box(siphash(&s))), &U32_VALUES),
    );
    c.bench(
        "sip",
        ParameterizedBenchmark::new("u64", |b, s| b.iter(|| black_box(siphash(&s))), &U64_VALUES),
    );
    c.bench(
        "sip",
        ParameterizedBenchmark::new("u128", |b, s| b.iter(|| black_box(siphash(&s))), &U128_VALUES),
    );
    c.bench(
        "sip",
        ParameterizedBenchmark::new("string", |b, s| b.iter(|| black_box(siphash(&s))), &VALUES),
    );
}

criterion_main!(benches);
criterion_group!(benches, bench_ahash, bench_fallback, bench_fx, bench_fnv, bench_sea, bench_sip);
<commit_msg>reenable all bench tests<commit_after>use criterion::*;
use std::hash::{Hash, Hasher};
use std::collections::hash_map::DefaultHasher;
use ahash::*;
use ahash::fallback::{FallbackHasher};
use fxhash::{FxHasher};

#[cfg(all(
any(target_arch = "x86", target_arch = "x86_64"),
target_feature = "aes"
))]
pub fn ahash<H: Hash>(b: H) -> u64 {
    let mut hasher = AHasher::default();
    b.hash(&mut hasher);
    hasher.finish()
}

fn fallbackhash<H: Hash>(b: H) -> u64 {
    let mut hasher = FallbackHasher::default();
    b.hash(&mut hasher);
    hasher.finish()
}

fn fnvhash<H: Hash>(b: H) -> u64 {
    let mut hasher = fnv::FnvHasher::default();
    b.hash(&mut hasher);
    hasher.finish()
}

fn siphash<H: Hash>(b: H) -> u64 {
    let mut hasher = DefaultHasher::default();
    b.hash(&mut hasher);
    hasher.finish()
}

fn fxhash<H: Hash>(b: H) -> u64 {
    let mut hasher = FxHasher::default();
    b.hash(&mut hasher);
    hasher.finish()
}

fn seahash<H: Hash>(b: H) -> u64 {
    let mut hasher = seahash::SeaHasher::default();
    b.hash(&mut hasher);
    hasher.finish()
}

const VALUES: [&str; 10] = ["1",
    "123",
    "1234",
    "1234567",
    "12345678",
    "123456789012345",
    "1234567890123456",
    "123456789012345678901234",
    "12345678901234567890123456789012345678901234567890123456789012345678",
    "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012"];

const U8_VALUES: [u32; 1] = [8];
const U16_VALUES: [u16; 1] = [16];
const U32_VALUES: [u32; 1] = [32];
const U64_VALUES: [u64; 1] = [64];
const U128_VALUES: [u128; 1] = [128];

#[cfg(all(
any(target_arch = "x86", target_arch = "x86_64"),
target_feature = "aes"
))]
fn bench_ahash(c: &mut Criterion) {
    c.bench(
        "ahash",
        ParameterizedBenchmark::new("u8", |b, s| b.iter(|| black_box(ahash(&s))), &U8_VALUES),
    );
    c.bench(
        "ahash",
        ParameterizedBenchmark::new("u16", |b, s| b.iter(|| black_box(ahash(&s))), &U16_VALUES),
    );
    c.bench(
        "ahash",
        ParameterizedBenchmark::new("u32", |b, s| b.iter(|| black_box(ahash(&s))), &U32_VALUES),
    );
    c.bench(
        "ahash",
        ParameterizedBenchmark::new("u64", |b, s| b.iter(|| black_box(ahash(&s))), &U64_VALUES),
    );
    c.bench(
        "ahash",
        ParameterizedBenchmark::new("u128", |b, s| b.iter(|| black_box(ahash(&s))), &U128_VALUES),
    );
    c.bench(
        "ahash",
        ParameterizedBenchmark::new("string", |b, s| b.iter(|| black_box(ahash(&s))), &VALUES),
    );
}

fn bench_fallback(c: &mut Criterion) {
    c.bench(
        "fallback",
        ParameterizedBenchmark::new("u8", |b, s| b.iter(|| black_box(fallbackhash(&s))), &U8_VALUES),
    );
    c.bench(
        "fallback",
        ParameterizedBenchmark::new("u16", |b, s| b.iter(|| black_box(fallbackhash(&s))), &U16_VALUES),
    );
    c.bench(
        "fallback",
        ParameterizedBenchmark::new("u32", |b, s| b.iter(|| black_box(fallbackhash(&s))), &U32_VALUES),
    );
    c.bench(
        "fallback",
        ParameterizedBenchmark::new("u64", |b, s| b.iter(|| black_box(fallbackhash(&s))), &U64_VALUES),
    );
    c.bench(
        "fallback",
        ParameterizedBenchmark::new("u128", |b, s| b.iter(|| black_box(fallbackhash(&s))), &U128_VALUES),
    );
    c.bench(
        "fallback",
        ParameterizedBenchmark::new("string", |b, s| b.iter(|| black_box(fallbackhash(&s))), &VALUES),
    );
}

fn bench_fx(c: &mut Criterion) {
    c.bench(
        "fx",
        ParameterizedBenchmark::new("u8", |b, s| b.iter(|| black_box(fxhash(&s))), &U8_VALUES),
    );
    c.bench(
        "fx",
        ParameterizedBenchmark::new("u16", |b, s| b.iter(|| black_box(fxhash(&s))), &U16_VALUES),
    );
    c.bench(
        "fx",
        ParameterizedBenchmark::new("u32", |b, s| b.iter(|| black_box(fxhash(&s))), &U32_VALUES),
    );
    c.bench(
        "fx",
        ParameterizedBenchmark::new("u64", |b, s| b.iter(|| black_box(fxhash(&s))), &U64_VALUES),
    );
    c.bench(
        "fx",
        ParameterizedBenchmark::new("u128", |b, s| b.iter(|| black_box(fxhash(&s))), &U128_VALUES),
    );
    c.bench(
        "fx",
        ParameterizedBenchmark::new("string", |b, s| b.iter(|| black_box(fxhash(&s))), &VALUES),
    );
}

fn bench_fnv(c: &mut Criterion) {
    c.bench(
        "fnv",
        ParameterizedBenchmark::new("u8", |b, s| b.iter(|| black_box(fnvhash(&s))), &U8_VALUES),
    );
    c.bench(
        "fnv",
        ParameterizedBenchmark::new("u16", |b, s| b.iter(|| black_box(fnvhash(&s))), &U16_VALUES),
    );
    c.bench(
        "fnv",
        ParameterizedBenchmark::new("u32", |b, s| b.iter(|| black_box(fnvhash(&s))), &U32_VALUES),
    );
    c.bench(
        "fnv",
        ParameterizedBenchmark::new("u64", |b, s| b.iter(|| black_box(fnvhash(&s))), &U64_VALUES),
    );
    c.bench(
        "fnv",
        ParameterizedBenchmark::new("u128", |b, s| b.iter(|| black_box(fnvhash(&s))), &U128_VALUES),
    );
    c.bench(
        "fnv",
        ParameterizedBenchmark::new("string", |b, s| b.iter(|| black_box(fnvhash(&s))), &VALUES),
    );
}

fn bench_sea(c: &mut Criterion) {
    c.bench(
        "sea",
        ParameterizedBenchmark::new("string", |b, s| b.iter(|| black_box(seahash(&s))), &VALUES),
    );
}

fn bench_sip(c: &mut Criterion) {
    c.bench(
        "sip",
        ParameterizedBenchmark::new("u8", |b, s| b.iter(|| black_box(siphash(&s))), &U8_VALUES),
    );
    c.bench(
        "sip",
        ParameterizedBenchmark::new("u16", |b, s| b.iter(|| black_box(siphash(&s))), &U16_VALUES),
    );
    c.bench(
        "sip",
        ParameterizedBenchmark::new("u32", |b, s| b.iter(|| black_box(siphash(&s))), &U32_VALUES),
    );
    c.bench(
        "sip",
        ParameterizedBenchmark::new("u64", |b, s| b.iter(|| black_box(siphash(&s))), &U64_VALUES),
    );
    c.bench(
        "sip",
        ParameterizedBenchmark::new("u128", |b, s| b.iter(|| black_box(siphash(&s))), &U128_VALUES),
    );
    c.bench(
        "sip",
        ParameterizedBenchmark::new("string", |b, s| b.iter(|| black_box(siphash(&s))), &VALUES),
    );
}

criterion_main!(benches);
criterion_group!(benches, bench_ahash, bench_fallback, bench_fx, bench_fnv, bench_sea, bench_sip);
<|endoftext|>


<commit_before>//! Higher level libtls API wrappers to use along with the Rust
//! standard library

use super::{TlsContext, TlsConfig};
use std::io;
use std::io::{Read, Write};
use std::net::TcpStream;

pub struct TlsConnection {
    cfg: TlsConfig,
}
impl TlsConnection {
    pub fn new() -> Option<TlsConnection> {
        if let Some(cfg) = TlsConfig::new() {
            Some(TlsConnection { cfg: cfg })
        } else {
            None
        }
    }

    /// Connect to server, and process the TLS handshake
    pub fn connect(self, hostname: &str, port: &str) -> io::Result<TlsStream> {
        let mut c = try!(TlsStream::new_client());
        try!(c.configure(self.cfg));
        try!(c.connect_servername(hostname, port, ""));
        if let Err(err) = c.handshake() {
            if err.wants_more() {
                try!(c.handshake());
            } else {
                return Err(io::Error::from(err));
            }
        }
        Ok(TlsStream { ctx: c })
    }

    pub fn set_ca_file(&mut self, path: &str) -> Option<()> {
        self.cfg.set_ca_file(path)
    }
    pub fn set_ca_path(&mut self, path: &str) -> Option<()> {
        self.cfg.set_ca_path(path)
    }
    pub fn set_ca_mem(&mut self, ca: &str) -> Option<()> {
        self.cfg.set_ca_mem(ca)
    }
    pub fn set_verify_depth(&mut self, depth: i32) {
        self.cfg.set_verify_depth(depth)
    }
}

pub struct TlsStream {
    ctx: TlsContext,
}

impl TlsStream {
    /// Convinience method to create TlsContext clients
    fn new_client() -> io::Result<TlsContext> {
        TlsContext::new_client()
            .ok_or(io::Error::new(io::ErrorKind::Other, "Failed to create new TLS context"))
    }

    /// Close the connection
    pub fn shutdown(&mut self) -> io::Result<()> {
        if let Err(err) = self.ctx.close() {
            if err.wants_more() {
                try!(self.ctx.close());
            } else {
                return Err(io::Error::from(err));
            }
        }
        Ok(())
    }

    /// Create a new TLS stream from an existing TCP stream
    pub fn from_tcp_stream(tcp: TcpStream, servername: &str) -> io::Result<TlsStream> {
        let mut c = try!(TlsStream::new_client());
        try!(c.connect_socket(tcp, servername)
              .map_err(|msg| io::Error::new(io::ErrorKind::Other, msg)));
        Ok(TlsStream { ctx: c })
    }
}

impl Read for TlsStream {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.ctx
            .read(buf)
            .map_err(|err| io::Error::from(err))
    }
}

impl Write for TlsStream {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.ctx
            .write(buf)
            .map_err(|err| io::Error::from(err))
    }
    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

impl Drop for TlsStream {
    fn drop(&mut self) {
        let _ = self.ctx.close();
    }
}
<commit_msg>Add methods to TlsConnection/TlsStream<commit_after>//! Higher level libtls API wrappers to use along with the Rust
//! standard library

use super::{TlsContext, TlsConfig};
use std::io;
use std::io::{Read, Write};
use std::net::TcpStream;

pub struct TlsConnection {
    cfg: TlsConfig,
}
impl TlsConnection {
    pub fn new() -> Option<TlsConnection> {
        if let Some(cfg) = TlsConfig::new() {
            Some(TlsConnection { cfg: cfg })
        } else {
            None
        }
    }

    /// Connect to server, and process the TLS handshake
    pub fn connect(self, hostname: &str, port: &str) -> io::Result<TlsStream> {
        let mut c = try!(TlsStream::new_client());
        try!(c.configure(self.cfg));
        try!(c.connect_servername(hostname, port, ""));
        if let Err(err) = c.handshake() {
            if err.wants_more() {
                try!(c.handshake());
            } else {
                return Err(io::Error::from(err));
            }
        }
        Ok(TlsStream { ctx: c })
    }

    pub fn set_ca_file(&mut self, path: &str) -> Option<()> {
        self.cfg.set_ca_file(path)
    }
    pub fn set_ca_path(&mut self, path: &str) -> Option<()> {
        self.cfg.set_ca_path(path)
    }
    pub fn set_ca_mem(&mut self, ca: &str) -> Option<()> {
        self.cfg.set_ca_mem(ca)
    }
    pub fn set_verify_depth(&mut self, depth: i32) {
        self.cfg.set_verify_depth(depth)
    }
    pub fn set_protocols(&mut self, protocols: &str) -> Option<()> {
        self.cfg.set_protocols(protocols)
    }
    pub fn set_ciphers(&mut self, ciphers: &str) -> Option<()> {
        self.cfg.set_ciphers(ciphers)
    }
    pub fn insecure_noverifycert(&mut self) {
        self.cfg.insecure_noverifycert()
    }
    pub fn insecure_noverifyname(&mut self) {
        self.cfg.insecure_noverifyname()
    }
}

pub struct TlsStream {
    ctx: TlsContext,
}

impl TlsStream {
    /// Convinience method to create TlsContext clients
    fn new_client() -> io::Result<TlsContext> {
        TlsContext::new_client()
            .ok_or(io::Error::new(io::ErrorKind::Other, "Failed to create new TLS context"))
    }

    /// Close the connection
    pub fn shutdown(&mut self) -> io::Result<()> {
        if let Err(err) = self.ctx.close() {
            if err.wants_more() {
                try!(self.ctx.close());
            } else {
                return Err(io::Error::from(err));
            }
        }
        Ok(())
    }

    /// Create a new TLS stream from an existing TCP stream
    pub fn from_tcp_stream(tcp: TcpStream, servername: &str) -> io::Result<TlsStream> {
        let mut c = try!(TlsStream::new_client());
        try!(c.connect_socket(tcp, servername)
              .map_err(|msg| io::Error::new(io::ErrorKind::Other, msg)));
        Ok(TlsStream { ctx: c })
    }

    pub fn certificate_issuer(&self) -> String {
        self.ctx.peer_cert_issuer()
    }
    pub fn certificate_hash(&self) -> String {
        self.ctx.peer_cert_hash()
    }
    pub fn certificate_subject(&self) -> String {
        self.ctx.peer_cert_subject()
    }
    pub fn version(&self) -> String {
        self.ctx.conn_version()
    }
    pub fn cipher(&self) -> String {
        self.ctx.conn_cipher()
    }
}

impl Read for TlsStream {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.ctx
            .read(buf)
            .map_err(|err| io::Error::from(err))
    }
}

impl Write for TlsStream {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.ctx
            .write(buf)
            .map_err(|err| io::Error::from(err))
    }
    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

impl Drop for TlsStream {
    fn drop(&mut self) {
        let _ = self.ctx.close();
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

use std::net::TcpStream;
use std::time::Duration;
use std::sync::{Arc, Mutex};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::mpsc::{self, Sender};
use std::thread::{self, JoinHandle};
use util::codec::rpc;
use util::make_std_tcp_conn;
use protobuf::{self, MessageStatic};
use super::Result;

const MAX_PD_SEND_RETRY_COUNT: usize = 100;

pub trait TRpcClient: Sync + Send {
    fn send<M, P>(&self, msg_id: u64, message: &M) -> Result

        where M: protobuf::Message,
              P: protobuf::Message + MessageStatic;
    fn post<M: protobuf::Message + ?Sized>(&self, msg_id: u64, message: &M) -> Result<()>;
}

#[derive(Debug)]
struct RpcClientCore {
    addrs: Vec<String>,
    // Try to connect pd with round-robin.
    next_index: usize,
    stream: Option<TcpStream>,
}

fn send_msg<M: protobuf::Message + ?Sized>(stream: &mut TcpStream,
                                           msg_id: u64,
                                           message: &M)
                                           -> Result<(u64, Vec<u8>)> {
    try!(stream.set_write_timeout(Some(Duration::from_secs(SOCKET_WRITE_TIMEOUT))));
    try!(rpc::encode_msg(stream, msg_id, message));

    try!(stream.set_read_timeout(Some(Duration::from_secs(SOCKET_READ_TIMEOUT))));
    let (id, data) = try!(rpc::decode_data(stream));
    Ok((id, data))
}

impl RpcClientCore {
    fn new(dsn: &str) -> RpcClientCore {
        let addrs: Vec<String> = dsn.split(',').map(From::from).collect();
        RpcClientCore {
            addrs: addrs,
            next_index: 0,
            stream: None,
        }
    }

    fn try_connect(&mut self) -> Result<()> {
        let index = self.next_index;
        self.next_index = (self.next_index + 1) % self.addrs.len();

        let addr = self.addrs.get(index).unwrap();
        let stream = try!(make_std_tcp_conn(&**addr));
        self.stream = Some(stream);
        Ok(())
    }

    fn post_msg<M: protobuf::Message + ?Sized>(&mut self,
                                               msg_id: u64,
                                               message: &M)
                                               -> Result<Vec<u8>> {
        // If we post failed, we should retry.
        for _ in 0..MAX_PD_SEND_RETRY_COUNT {
            // If no stream, try connect first.
            if self.stream.is_none() {
                if let Err(e) = self.try_connect() {
                    warn!("connect pd failed {:?}", e);
                    continue;
                }
            }

            let mut stream = self.stream.take().unwrap();
            // We may send message to a not leader pd, retry.

            let (id, data) = match send_msg(&mut stream, msg_id, message) {
                Err(e) => {
                    warn!("send message to pd failed {:?}", e);
                    // TODO: figure out a better way to do backoff
                    thread::sleep(Duration::from_millis(50));
                    continue;
                }
                Ok((id, data)) => (id, data),
            };

            if id != msg_id {
                return Err(box_err!("pd response msg_id not match, want {}, got {}", msg_id, id));
            }

            self.stream = Some(stream);
            return Ok(data);
        }

        Err(box_err!("post message to pd failed"))
    }
}

#[derive(Debug)]
pub struct RpcClient {
    core: Mutex<RpcClientCore>,
}

const SOCKET_READ_TIMEOUT: u64 = 3;
const SOCKET_WRITE_TIMEOUT: u64 = 3;

impl RpcClient {
    pub fn new(dsn: &str) -> Result<RpcClient> {
        Ok(RpcClient { core: Mutex::new(RpcClientCore::new(dsn)) })
    }
}

impl TRpcClient for RpcClient {
    fn send<M, P>(&self, msg_id: u64, message: &M) -> Result

        where M: protobuf::Message,
              P: protobuf::Message + MessageStatic
    {
        let mut resp = P::new();
        let data = try!(self.core.lock().unwrap().post_msg(msg_id, message));
        try!(rpc::decode_body(&data, &mut resp));
        Ok(resp)
    }

    fn post<M: protobuf::Message + ?Sized>(&self, msg_id: u64, message: &M) -> Result<()> {
        let _ = try!(self.core.lock().unwrap().post_msg(msg_id, message));
        Ok(())
    }
}

#[derive(Debug)]
enum Msg {
    Rpc(u64, Box<protobuf::Message + Send>),
    Quit,
}

pub struct Client<C: TRpcClient + 'static> {
    msg_id: AtomicUsize,
    rpc_client: Arc<C>,
    tx: Mutex<Sender<Msg>>,
    handle: Option<JoinHandle<()>>,
}

impl<C: TRpcClient + 'static> Client<C> {
    pub fn new(rpc_client: C) -> Result<Client<C>> {
        let shared = Arc::new(rpc_client);
        let (tx, rx) = mpsc::channel();
        let handle = {
            let rpc_client = shared.clone();
            try!(thread::Builder::new()
                     .name("pd-client background worker".to_owned())
                     .spawn(move || {
                         info!("pd-client background worker starting");
                         while let Msg::Rpc(msg_id, msg) = rx.recv().unwrap() {
                             if let Err(e) = rpc_client.post(msg_id, msg.as_ref()) {
                                 error!("pd post error: {}", e);
                             } else {
                                 debug!("pd post done: {}", msg_id);
                             }
                         }
                         info!("pd-client background worker closing");
                     }))
        };
        Ok(Client {
            msg_id: AtomicUsize::new(0),
            rpc_client: shared.clone(),
            tx: Mutex::new(tx),
            handle: Some(handle),
        })
    }

    fn close(&mut self) {
        if let Err(e) = self.clone_tx().send(Msg::Quit) {
            error!("failed to send quit message to pd-client background worker: {}",
                   e);
        }
        let handle = self.handle.take().unwrap();
        if handle.join().is_err() {
            error!("failed to wait pd-client background worker quit");
        }
        info!("pd-client closed.");
    }

    pub fn send<M, P>(&self, message: &M) -> Result

        where M: protobuf::Message,
              P: protobuf::Message + MessageStatic
    {
        let id = self.alloc_msg_id();
        self.rpc_client.send(id, message)
    }

    pub fn post<M: protobuf::Message + Send>(&self, message: M) -> Result<()> {
        let id = self.alloc_msg_id();
        if let Err(e) = self.clone_tx().send(Msg::Rpc(id, box message)) {
            return Err(box_err!(format!("SendError: {:?}", e)));
        }
        Ok(())
    }

    fn alloc_msg_id(&self) -> u64 {
        self.msg_id.fetch_add(1, Ordering::Relaxed) as u64
    }

    fn clone_tx(&self) -> Sender<Msg> {
        let tx = self.tx.lock().unwrap();
        tx.clone()
    }
}

impl<C: TRpcClient + 'static> Drop for Client<C> {
    fn drop(&mut self) {
        self.close()
    }
}

#[cfg(test)]
mod tests {
    use std::net::TcpListener;
    use std::thread;
    use std::sync::Arc;
    use std::sync::atomic::{AtomicUsize, AtomicBool, Ordering};

    use super::super::{Result, PdClient};
    use super::*;
    use protobuf;
    use bytes::ByteBuf;
    use util::codec::rpc;
    use kvproto::{metapb, pdpb};
    use rand;
    use util::make_std_tcp_conn;

    struct MockRpcClient;

    impl MockRpcClient {
        fn reply(&self, req: &pdpb::Request) -> pdpb::Response {
            assert!(req.has_header());
            let header = req.get_header();
            let (uuid, cluster_id) = (header.get_uuid(), header.get_cluster_id());

            let mut resp = pdpb::Response::new();
            let mut header = pdpb::ResponseHeader::new();
            header.set_uuid(uuid.to_vec());
            header.set_cluster_id(cluster_id);

            match req.get_cmd_type() {
                pdpb::CommandType::AllocId => {
                    let mut alloc = pdpb::AllocIdResponse::new();
                    alloc.set_id(42);
                    resp.set_alloc_id(alloc);
                }
                pdpb::CommandType::PutMeta => {
                    let meta = req.get_put_meta();
                    if meta.get_meta_type() == pdpb::MetaType::StoreType {
                        let store = meta.get_store();
                        assert_eq!(store.get_id(), 233);
                        assert_eq!(store.get_address(), "localhost");
                    }
                }
                _ => {
                    let mut err = pdpb::Error::new();
                    err.set_message(String::from("I've got a bad feeling about this"));
                    header.set_error(err);
                }
            }

            resp.set_header(header);
            resp.set_cmd_type(req.get_cmd_type());
            resp
        }
    }

    impl TRpcClient for MockRpcClient {
        fn send<M, P>(&self, msg_id: u64, message: &M) -> Result

            where M: protobuf::Message,
                  P: protobuf::Message + Default
        {
            let mut buf = ByteBuf::mut_with_capacity(128);
            rpc::encode_msg(&mut buf, msg_id, message).unwrap();
            let mut req = pdpb::Request::new();
            rpc::decode_msg(&mut buf.flip(), &mut req).unwrap();

            let resp = self.reply(&req);
            let mut buf = ByteBuf::mut_with_capacity(128);
            rpc::encode_msg(&mut buf, msg_id, &resp).unwrap();
            let mut msg = P::default();
            rpc::decode_msg(&mut buf.flip(), &mut msg).unwrap();
            Ok(msg)
        }

        fn post<M: protobuf::Message + ?Sized>(&self, _: u64, _: &M) -> Result<()> {
            Ok(())
        }
    }

    #[test]
    fn test_pd_client() {
        let mut client = Client::new(MockRpcClient).unwrap();
        assert_eq!(client.alloc_id().unwrap(), 42u64);
        assert!(client.is_cluster_bootstrapped(1).is_err());

        let mut store = metapb::Store::new();
        store.set_id(233);
        store.set_address("localhost".to_owned());
        assert!(client.put_store(1, store).is_ok());
    }

    fn start_pd_server(index: usize,
                       leader_index: Arc<AtomicUsize>,
                       quit: Arc<AtomicBool>)
                       -> (thread::JoinHandle<()>, String) {
        let l = TcpListener::bind("127.0.0.1:0").unwrap();

        let addr = format!("{}", l.local_addr().unwrap());

        let h = thread::spawn(move || {
            loop {
                let (mut stream, _) = l.accept().unwrap();

                if quit.load(Ordering::SeqCst) {
                    return;
                }

                stream.set_nodelay(true).unwrap();

                let leader = leader_index.load(Ordering::SeqCst);
                if leader != index {
                    continue;
                }

                let (id, data) = rpc::decode_data(&mut stream).unwrap();
                rpc::encode_data(&mut stream, id, &data).unwrap();
            }
        });

        (h, addr)
    }

    #[test]
    fn test_rpc_client() {
        let leader = Arc::new(AtomicUsize::new(0));
        let quit = Arc::new(AtomicBool::new(false));
        let mut handlers = vec![];
        let mut addrs = vec![];

        let count = 3;
        for i in 0..count {
            let (h, addr) = start_pd_server(i, leader.clone(), quit.clone());
            handlers.push(h);
            addrs.push(addr);
        }

        let dsn = addrs.join(",");

        let msg = pdpb::Request::new();
        let client = RpcClient::new(&dsn).unwrap();

        for i in 0..10 {
            client.post(i as u64, &msg).unwrap();

            // select a leader randomly
            leader.store(rand::random::<usize>() % 3, Ordering::SeqCst);
        }

        quit.store(true, Ordering::SeqCst);

        // connect the server so that we can close the thread.
        for addr in addrs {
            make_std_tcp_conn(&*addr).unwrap();
        }

        for h in handlers {
            h.join().unwrap();
        }
    }
}
<commit_msg>pd: fix retry (#409)<commit_after>// Copyright 2016 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

use std::net::TcpStream;
use std::time::Duration;
use std::sync::{Arc, Mutex};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::mpsc::{self, Sender};
use std::thread::{self, JoinHandle};
use util::codec::rpc;
use util::make_std_tcp_conn;
use protobuf::{self, MessageStatic};
use super::Result;

const MAX_PD_SEND_RETRY_COUNT: usize = 100;

pub trait TRpcClient: Sync + Send {
    fn send<M, P>(&self, msg_id: u64, message: &M) -> Result

        where M: protobuf::Message,
              P: protobuf::Message + MessageStatic;
    fn post<M: protobuf::Message + ?Sized>(&self, msg_id: u64, message: &M) -> Result<()>;
}

#[derive(Debug)]
struct RpcClientCore {
    addrs: Vec<String>,
    // Try to connect pd with round-robin.
    next_index: usize,
    stream: Option<TcpStream>,
}

fn send_msg<M: protobuf::Message + ?Sized>(stream: &mut TcpStream,
                                           msg_id: u64,
                                           message: &M)
                                           -> Result<(u64, Vec<u8>)> {
    try!(stream.set_write_timeout(Some(Duration::from_secs(SOCKET_WRITE_TIMEOUT))));
    try!(rpc::encode_msg(stream, msg_id, message));

    try!(stream.set_read_timeout(Some(Duration::from_secs(SOCKET_READ_TIMEOUT))));
    let (id, data) = try!(rpc::decode_data(stream));
    Ok((id, data))
}

impl RpcClientCore {
    fn new(dsn: &str) -> RpcClientCore {
        let addrs: Vec<String> = dsn.split(',').map(From::from).collect();
        RpcClientCore {
            addrs: addrs,
            next_index: 0,
            stream: None,
        }
    }

    fn try_connect(&mut self) -> Result<()> {
        let index = self.next_index;
        self.next_index = (self.next_index + 1) % self.addrs.len();

        let addr = self.addrs.get(index).unwrap();
        let stream = try!(make_std_tcp_conn(&**addr));
        self.stream = Some(stream);
        Ok(())
    }

    fn post_msg<M: protobuf::Message + ?Sized>(&mut self,
                                               msg_id: u64,
                                               message: &M)
                                               -> Result<Vec<u8>> {
        // If we post failed, we should retry.
        for _ in 0..MAX_PD_SEND_RETRY_COUNT {
            // If no stream, try connect first.
            if self.stream.is_none() {
                if let Err(e) = self.try_connect() {
                    warn!("connect pd failed {:?}", e);
                    // TODO: figure out a better way to do backoff
                    thread::sleep(Duration::from_millis(50));
                    continue;
                }
            }

            let mut stream = self.stream.take().unwrap();
            // We may send message to a not leader pd, retry.

            let (id, data) = match send_msg(&mut stream, msg_id, message) {
                Err(e) => {
                    warn!("send message to pd failed {:?}", e);
                    // TODO: figure out a better way to do backoff
                    thread::sleep(Duration::from_millis(50));
                    continue;
                }
                Ok((id, data)) => (id, data),
            };

            if id != msg_id {
                return Err(box_err!("pd response msg_id not match, want {}, got {}", msg_id, id));
            }

            self.stream = Some(stream);
            return Ok(data);
        }

        Err(box_err!("post message to pd failed"))
    }
}

#[derive(Debug)]
pub struct RpcClient {
    core: Mutex<RpcClientCore>,
}

const SOCKET_READ_TIMEOUT: u64 = 3;
const SOCKET_WRITE_TIMEOUT: u64 = 3;

impl RpcClient {
    pub fn new(dsn: &str) -> Result<RpcClient> {
        Ok(RpcClient { core: Mutex::new(RpcClientCore::new(dsn)) })
    }
}

impl TRpcClient for RpcClient {
    fn send<M, P>(&self, msg_id: u64, message: &M) -> Result

        where M: protobuf::Message,
              P: protobuf::Message + MessageStatic
    {
        let mut resp = P::new();
        let data = try!(self.core.lock().unwrap().post_msg(msg_id, message));
        try!(rpc::decode_body(&data, &mut resp));
        Ok(resp)
    }

    fn post<M: protobuf::Message + ?Sized>(&self, msg_id: u64, message: &M) -> Result<()> {
        let _ = try!(self.core.lock().unwrap().post_msg(msg_id, message));
        Ok(())
    }
}

#[derive(Debug)]
enum Msg {
    Rpc(u64, Box<protobuf::Message + Send>),
    Quit,
}

pub struct Client<C: TRpcClient + 'static> {
    msg_id: AtomicUsize,
    rpc_client: Arc<C>,
    tx: Mutex<Sender<Msg>>,
    handle: Option<JoinHandle<()>>,
}

impl<C: TRpcClient + 'static> Client<C> {
    pub fn new(rpc_client: C) -> Result<Client<C>> {
        let shared = Arc::new(rpc_client);
        let (tx, rx) = mpsc::channel();
        let handle = {
            let rpc_client = shared.clone();
            try!(thread::Builder::new()
                     .name("pd-client background worker".to_owned())
                     .spawn(move || {
                         info!("pd-client background worker starting");
                         while let Msg::Rpc(msg_id, msg) = rx.recv().unwrap() {
                             if let Err(e) = rpc_client.post(msg_id, msg.as_ref()) {
                                 error!("pd post error: {}", e);
                             } else {
                                 debug!("pd post done: {}", msg_id);
                             }
                         }
                         info!("pd-client background worker closing");
                     }))
        };
        Ok(Client {
            msg_id: AtomicUsize::new(0),
            rpc_client: shared.clone(),
            tx: Mutex::new(tx),
            handle: Some(handle),
        })
    }

    fn close(&mut self) {
        if let Err(e) = self.clone_tx().send(Msg::Quit) {
            error!("failed to send quit message to pd-client background worker: {}",
                   e);
        }
        let handle = self.handle.take().unwrap();
        if handle.join().is_err() {
            error!("failed to wait pd-client background worker quit");
        }
        info!("pd-client closed.");
    }

    pub fn send<M, P>(&self, message: &M) -> Result

        where M: protobuf::Message,
              P: protobuf::Message + MessageStatic
    {
        let id = self.alloc_msg_id();
        self.rpc_client.send(id, message)
    }

    pub fn post<M: protobuf::Message + Send>(&self, message: M) -> Result<()> {
        let id = self.alloc_msg_id();
        if let Err(e) = self.clone_tx().send(Msg::Rpc(id, box message)) {
            return Err(box_err!(format!("SendError: {:?}", e)));
        }
        Ok(())
    }

    fn alloc_msg_id(&self) -> u64 {
        self.msg_id.fetch_add(1, Ordering::Relaxed) as u64
    }

    fn clone_tx(&self) -> Sender<Msg> {
        let tx = self.tx.lock().unwrap();
        tx.clone()
    }
}

impl<C: TRpcClient + 'static> Drop for Client<C> {
    fn drop(&mut self) {
        self.close()
    }
}

#[cfg(test)]
mod tests {
    use std::net::TcpListener;
    use std::thread;
    use std::sync::Arc;
    use std::sync::atomic::{AtomicUsize, AtomicBool, Ordering};

    use super::super::{Result, PdClient};
    use super::*;
    use protobuf;
    use bytes::ByteBuf;
    use util::codec::rpc;
    use kvproto::{metapb, pdpb};
    use rand;
    use util::make_std_tcp_conn;

    struct MockRpcClient;

    impl MockRpcClient {
        fn reply(&self, req: &pdpb::Request) -> pdpb::Response {
            assert!(req.has_header());
            let header = req.get_header();
            let (uuid, cluster_id) = (header.get_uuid(), header.get_cluster_id());

            let mut resp = pdpb::Response::new();
            let mut header = pdpb::ResponseHeader::new();
            header.set_uuid(uuid.to_vec());
            header.set_cluster_id(cluster_id);

            match req.get_cmd_type() {
                pdpb::CommandType::AllocId => {
                    let mut alloc = pdpb::AllocIdResponse::new();
                    alloc.set_id(42);
                    resp.set_alloc_id(alloc);
                }
                pdpb::CommandType::PutMeta => {
                    let meta = req.get_put_meta();
                    if meta.get_meta_type() == pdpb::MetaType::StoreType {
                        let store = meta.get_store();
                        assert_eq!(store.get_id(), 233);
                        assert_eq!(store.get_address(), "localhost");
                    }
                }
                _ => {
                    let mut err = pdpb::Error::new();
                    err.set_message(String::from("I've got a bad feeling about this"));
                    header.set_error(err);
                }
            }

            resp.set_header(header);
            resp.set_cmd_type(req.get_cmd_type());
            resp
        }
    }

    impl TRpcClient for MockRpcClient {
        fn send<M, P>(&self, msg_id: u64, message: &M) -> Result

            where M: protobuf::Message,
                  P: protobuf::Message + Default
        {
            let mut buf = ByteBuf::mut_with_capacity(128);
            rpc::encode_msg(&mut buf, msg_id, message).unwrap();
            let mut req = pdpb::Request::new();
            rpc::decode_msg(&mut buf.flip(), &mut req).unwrap();

            let resp = self.reply(&req);
            let mut buf = ByteBuf::mut_with_capacity(128);
            rpc::encode_msg(&mut buf, msg_id, &resp).unwrap();
            let mut msg = P::default();
            rpc::decode_msg(&mut buf.flip(), &mut msg).unwrap();
            Ok(msg)
        }

        fn post<M: protobuf::Message + ?Sized>(&self, _: u64, _: &M) -> Result<()> {
            Ok(())
        }
    }

    #[test]
    fn test_pd_client() {
        let mut client = Client::new(MockRpcClient).unwrap();
        assert_eq!(client.alloc_id().unwrap(), 42u64);
        assert!(client.is_cluster_bootstrapped(1).is_err());

        let mut store = metapb::Store::new();
        store.set_id(233);
        store.set_address("localhost".to_owned());
        assert!(client.put_store(1, store).is_ok());
    }

    fn start_pd_server(index: usize,
                       leader_index: Arc<AtomicUsize>,
                       quit: Arc<AtomicBool>)
                       -> (thread::JoinHandle<()>, String) {
        let l = TcpListener::bind("127.0.0.1:0").unwrap();

        let addr = format!("{}", l.local_addr().unwrap());

        let h = thread::spawn(move || {
            loop {
                let (mut stream, _) = l.accept().unwrap();

                if quit.load(Ordering::SeqCst) {
                    return;
                }

                stream.set_nodelay(true).unwrap();

                let leader = leader_index.load(Ordering::SeqCst);
                if leader != index {
                    continue;
                }

                let (id, data) = rpc::decode_data(&mut stream).unwrap();
                rpc::encode_data(&mut stream, id, &data).unwrap();
            }
        });

        (h, addr)
    }

    #[test]
    fn test_rpc_client() {
        let leader = Arc::new(AtomicUsize::new(0));
        let quit = Arc::new(AtomicBool::new(false));
        let mut handlers = vec![];
        let mut addrs = vec![];

        let count = 3;
        for i in 0..count {
            let (h, addr) = start_pd_server(i, leader.clone(), quit.clone());
            handlers.push(h);
            addrs.push(addr);
        }

        let dsn = addrs.join(",");

        let msg = pdpb::Request::new();
        let client = RpcClient::new(&dsn).unwrap();

        for i in 0..10 {
            client.post(i as u64, &msg).unwrap();

            // select a leader randomly
            leader.store(rand::random::<usize>() % 3, Ordering::SeqCst);
        }

        quit.store(true, Ordering::SeqCst);

        // connect the server so that we can close the thread.
        for addr in addrs {
            make_std_tcp_conn(&*addr).unwrap();
        }

        for h in handlers {
            h.join().unwrap();
        }
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

use std::collections::BTreeSet;
use std::fmt::{self, Display};
use parse::NextPrev;

#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub struct Range(pub char, pub char);

impl fmt::Display for Range {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({}, {})", self.0, self.1)
    }
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Set(BTreeSet<Range>);

impl fmt::Display for Set {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let Set(ref set) = *self;
        let len = BTreeSet::len(set);

        for (count, s) in set.iter().enumerate() {
            if count < len - 1 { try!(write!(f, "{}, ", s)) }
            else { return write!(f, "{}", s) }
        }

        Ok(())
    }
}

impl Set {
    pub fn new() -> Self { Set(BTreeSet::new()) }
    pub fn insert(&mut self, value: Range) {
        let mut ret = BTreeSet::new();
        // value is a complete subset of one of the other ranges.
        let mut subset = false;

        // Borrowing self blocks later operation. Add a new scope.
        {   let Set(ref set) = *self;

            let Range(mut min_val, mut max_val) = value;
            if min_val > max_val { panic!("First value cannot be greater than the second.") }

            // Loop over set adding old disjoint pieces and supersets back.
            // When partially overlapped, expand value to the union. At the
            // end, insert union after it has been fully expanded.
            for &Range(min, max) in &*set {
                // value overlaps at the beginning.
                if min_val < min && max_val >= min && max_val < max { max_val = max }
                // value overlaps at the end.
                else if min_val > min && min_val <= max && max_val > max { min_val = min }
                // value is entirely contained between min and max. Insert original
                // into new array because new is a subset.
                else if min_val >= min && max_val <= max {
                    ret.insert(Range(min, max));
                    subset = true;
                }
                // value is a superset to the current so don't add current.
                else if min_val < min && max_val > max {}
                // value is disjoint with current so add current.
                else { ret.insert(Range(min, max)); }
            }

            // Insert value only when it's not a subset.
            if !subset { ret.insert(Range(min_val, max_val)); }
        }

        *self = Set(ret);
    }
    pub fn remove(&mut self, value: Range) {
        let mut ret = BTreeSet::new();

        // Borrowing self blocks later modification. Make a new scope to contain it.
        {   let Set(ref set) = *self;

            let Range(min_val, max_val) = value;
            if min_val > max_val { panic!("First value cannot be greater than the second.") }

            // Loop over set inserting whatever doesn't intersect.
            for &Range(min, max) in &*set {
                // value overlaps at the beginning.
                if min_val <= min && max_val >= min && max_val < max { ret.insert(Range(max_val.next(), max)); }
                // value overlaps at the end.
                else if min_val > min && min_val <= max && max_val >= max { ret.insert(Range(min, min_val.prev())); }
                // value is entirely contained between min and max. Split set
                // into two pieces.
                else if min_val > min && max_val < max {
                    ret.insert(Range(min, min_val.prev()));
                    ret.insert(Range(max_val.next(), max));

                    // Current piece was a superset so value cannot be anywhere else.
                    break;
                // value is a superset to the current so don't add current.
                } else if min_val <= min && max_val >= max {}
                // value is disjoint with current so add current.
                else { ret.insert(Range(min, max)); }
            }
        }

        *self = Set(ret)
    }
    pub fn union(&mut self, value: Self) {
        for x in value.0 { self.insert(x) }
    }
}

#[cfg(test)]
mod test {
    use super::{Range, Set};

    fn generate(vec: Vec<(char, char)>) -> Set {
        let mut set = Set::new();

        for (a, b) in vec {
            set.insert(Range(a, b));
        }

        set
    }
    #[test]
    fn insert_partial_overlap() {
        let set1 = generate(vec![('3', '5'), ('4', '6')]);
        let set2 = generate(vec![('3', '5'), ('1', '4')]);

        let other1 = generate(vec![('3', '6')]);
        let other2 = generate(vec![('1', '5')]);

        assert_eq!(other1, set1);
        assert_eq!(other2, set2);
    }
    #[test]
    fn insert_subset() {
        let set1 = generate(vec![('1', '5'), ('2', '3')]); // Complete overlap.
        let set2 = generate(vec![('1', '5'), ('1', '3')]); // Left is exact.
        let set3 = generate(vec![('1', '5'), ('2', '5')]); // Right is exact.
        let set4 = generate(vec![('1', '5'), ('1', '5')]); // Both are exact.

        let other = generate(vec![('1', '5')]);

        assert_eq!(set1, other);
        assert_eq!(set2, other);
        assert_eq!(set3, other);
        assert_eq!(set4, other);
    }
    #[test]
    fn insert_superset() {
        let set   = generate(vec![('3', '5'), ('2', '6')]);
        let other = generate(vec![('2', '6')]);

        assert_eq!(other, set);
    }
    #[test]
    #[should_panic]
    fn panic_on_decreasing_order() {
        generate(vec![('5', '3')]);
    }
    #[test]
    fn set_union() {
        let mut set1 = generate(vec![('1', '4'), ('5', '6')]);
        let set2 =     generate(vec![('0', '5'), ('8', '9')]);

        set1.union(set2);

        let other = generate(vec![('0', '6'), ('8', '9')]);
        assert_eq!(set1, other);
    }
    #[test]
    fn remove_partial_overlap() {
        let mut set1 = generate(vec![('5', '9')]);
        set1.remove(Range('3', '6')); // beginnings different.

        let mut set2 = generate(vec![('5', '9')]);
        set2.remove(Range('5', '6')); // beginnings same.

        let mut set3 = generate(vec![('2', '6')]);
        set3.remove(Range('5', '9')); // end different.

        let mut set4 = generate(vec![('2', '6')]);
        set4.remove(Range('5', '6')); // end same.

        let other12 = generate(vec![('7', '9')]);
        let other34 = generate(vec![('2', '4')]);

        assert_eq!(set1, other12);
        assert_eq!(set2, other12);
        assert_eq!(set3, other34);
        assert_eq!(set4, other34);
    }
    #[test]
    fn remove_subset() {
        let mut set = generate(vec![('1', '9')]);
        set.remove(Range('3', '6'));

        let other = generate(vec![('1', '2'), ('7', '9')]);

        assert_eq!(set, other);
    }
    #[test]
    fn remove_superset() {
        let mut set = generate(vec![('5', '6')]);
        set.remove(Range('3', '8'));

        let other = generate(vec![]);
        assert_eq!(set, other);
    }
    #[test]
    fn remove_disjoint() {
        let mut set = generate(vec![('2', '3')]);
        set.remove(Range('6', '8'));

        let other = generate(vec![('2', '3')]);
        assert_eq!(set, other);
    }
}
<commit_msg>Implement difference with tests<commit_after>#![allow(dead_code)]

use std::collections::BTreeSet;
use std::fmt::{self, Display};
use parse::NextPrev;

#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub struct Range(pub char, pub char);

impl fmt::Display for Range {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({}, {})", self.0, self.1)
    }
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Set(BTreeSet<Range>);

impl fmt::Display for Set {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let Set(ref set) = *self;
        let len = BTreeSet::len(set);

        for (count, s) in set.iter().enumerate() {
            if count < len - 1 { try!(write!(f, "{}, ", s)) }
            else { return write!(f, "{}", s) }
        }

        Ok(())
    }
}

impl Set {
    pub fn new() -> Self { Set(BTreeSet::new()) }
    pub fn insert(&mut self, value: Range) {
        let mut ret = BTreeSet::new();
        // value is a complete subset of one of the other ranges.
        let mut subset = false;

        // Borrowing self blocks later operation. Add a new scope.
        {   let Set(ref set) = *self;

            let Range(mut min_val, mut max_val) = value;
            if min_val > max_val { panic!("First value cannot be greater than the second.") }

            // Loop over set adding old disjoint pieces and supersets back.
            // When partially overlapped, expand value to the union. At the
            // end, insert union after it has been fully expanded.
            for &Range(min, max) in &*set {
                // value overlaps at the beginning.
                if min_val < min && max_val >= min && max_val < max { max_val = max }
                // value overlaps at the end.
                else if min_val > min && min_val <= max && max_val > max { min_val = min }
                // value is entirely contained between min and max. Insert original
                // into new array because new is a subset.
                else if min_val >= min && max_val <= max {
                    ret.insert(Range(min, max));
                    subset = true;
                }
                // value is a superset to the current so don't add current.
                else if min_val < min && max_val > max {}
                // value is disjoint with current so add current.
                else { ret.insert(Range(min, max)); }
            }

            // Insert value only when it's not a subset.
            if !subset { ret.insert(Range(min_val, max_val)); }
        }

        *self = Set(ret);
    }
    pub fn remove(&mut self, value: Range) {
        let mut ret = BTreeSet::new();

        // Borrowing self blocks later modification. Make a new scope to contain it.
        {   let Set(ref set) = *self;

            let Range(min_val, max_val) = value;
            if min_val > max_val { panic!("First value cannot be greater than the second.") }

            // Loop over set inserting whatever doesn't intersect.
            for &Range(min, max) in &*set {
                // value overlaps at the beginning.
                if min_val <= min && max_val >= min && max_val < max { ret.insert(Range(max_val.next(), max)); }
                // value overlaps at the end.
                else if min_val > min && min_val <= max && max_val >= max { ret.insert(Range(min, min_val.prev())); }
                // value is entirely contained between min and max. Split set
                // into two pieces.
                else if min_val > min && max_val < max {
                    ret.insert(Range(min, min_val.prev()));
                    ret.insert(Range(max_val.next(), max));

                    // Current piece was a superset so value cannot be anywhere else.
                    break;
                // value is a superset to the current so don't add current.
                } else if min_val <= min && max_val >= max {}
                // value is disjoint with current so add current.
                else { ret.insert(Range(min, max)); }
            }
        }

        *self = Set(ret)
    }
    pub fn union(&mut self, value: Self) {
        for x in value.0 { self.insert(x) }
    }
    pub fn difference(&mut self, value: Self) {
        for x in value.0 { self.remove(x) }
    }
}

#[cfg(test)]
mod test {
    use super::{Range, Set};

    fn generate(vec: Vec<(char, char)>) -> Set {
        let mut set = Set::new();

        for (a, b) in vec {
            set.insert(Range(a, b));
        }

        set
    }
    #[test]
    fn insert_partial_overlap() {
        let set1 = generate(vec![('3', '5'), ('4', '6')]);
        let set2 = generate(vec![('3', '5'), ('1', '4')]);

        let other1 = generate(vec![('3', '6')]);
        let other2 = generate(vec![('1', '5')]);

        assert_eq!(other1, set1);
        assert_eq!(other2, set2);
    }
    #[test]
    fn insert_subset() {
        let set1 = generate(vec![('1', '5'), ('2', '3')]); // Complete overlap.
        let set2 = generate(vec![('1', '5'), ('1', '3')]); // Left is exact.
        let set3 = generate(vec![('1', '5'), ('2', '5')]); // Right is exact.
        let set4 = generate(vec![('1', '5'), ('1', '5')]); // Both are exact.

        let other = generate(vec![('1', '5')]);

        assert_eq!(set1, other);
        assert_eq!(set2, other);
        assert_eq!(set3, other);
        assert_eq!(set4, other);
    }
    #[test]
    fn insert_superset() {
        let set   = generate(vec![('3', '5'), ('2', '6')]);
        let other = generate(vec![('2', '6')]);

        assert_eq!(other, set);
    }
    #[test]
    #[should_panic]
    fn panic_on_decreasing_order() {
        generate(vec![('5', '3')]);
    }
    #[test]
    fn set_union() {
        let mut set1 = generate(vec![('1', '4'), ('5', '6')]);
        let set2 =     generate(vec![('0', '5'), ('8', '9')]);

        set1.union(set2);

        let other = generate(vec![('0', '6'), ('8', '9')]);
        assert_eq!(set1, other);
    }
    #[test]
    fn remove_partial_overlap() {
        let mut set1 = generate(vec![('5', '9')]);
        set1.remove(Range('3', '6')); // beginnings different.

        let mut set2 = generate(vec![('5', '9')]);
        set2.remove(Range('5', '6')); // beginnings same.

        let mut set3 = generate(vec![('2', '6')]);
        set3.remove(Range('5', '9')); // end different.

        let mut set4 = generate(vec![('2', '6')]);
        set4.remove(Range('5', '6')); // end same.

        let other12 = generate(vec![('7', '9')]);
        let other34 = generate(vec![('2', '4')]);

        assert_eq!(set1, other12);
        assert_eq!(set2, other12);
        assert_eq!(set3, other34);
        assert_eq!(set4, other34);
    }
    #[test]
    fn remove_subset() {
        let mut set = generate(vec![('1', '9')]);
        set.remove(Range('3', '6'));

        let other = generate(vec![('1', '2'), ('7', '9')]);

        assert_eq!(set, other);
    }
    #[test]
    fn remove_superset() {
        let mut set = generate(vec![('5', '6')]);
        set.remove(Range('3', '8'));

        let other = generate(vec![]);
        assert_eq!(set, other);
    }
    #[test]
    fn remove_disjoint() {
        let mut set = generate(vec![('2', '3')]);
        set.remove(Range('6', '8'));

        let other = generate(vec![('2', '3')]);
        assert_eq!(set, other);
    }
    #[test]
    fn set_difference() {
        let mut set1 = generate(vec![('2', '7')]);
        let set2     = generate(vec![('0', '1'),   // disjoint left
                                     ('1', '2'),   // partial overlap left
                                     ('4', '5'),   // subset
                                     ('7', '8'),   // partial overlap right
                                     ('9', '9')]); // disjoint right
        let mut letters1 = generate(vec![('c', 'e')]);
        let     letters2 = generate(vec![('a', 'g')]); // superset

        set1.difference(set2);
        letters1.difference(letters2);

        let other_set     = generate(vec![('3', '3'), ('6', '6')]);
        let other_letters = generate(vec![]);

        assert_eq!(set1, other_set);
        assert_eq!(letters1, other_letters);
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

use std::collections::BTreeSet;
use std::fmt::{self, Display};
use parse::NextPrev;

#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub struct Range(pub char, pub char);

impl fmt::Display for Range {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({}, {})", self.0, self.1)
    }
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Set(BTreeSet<Range>);

impl fmt::Display for Set {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let Set(ref set) = *self;
        let len = BTreeSet::len(set);

        for (count, s) in set.iter().enumerate() {
            if count < len - 1 { try!(write!(f, "{}, ", s)) }
            else { return write!(f, "{}", s) }
        }

        Ok(())
    }
}

impl Set {
    pub fn new() -> Self { Set(BTreeSet::new()) }
    pub fn insert(&mut self, value: Range) {
        let mut ret = BTreeSet::new();
        // value is a complete subset of one of the other ranges.
        let mut subset = false;

        // Borrowing self blocks later operation. Add a new scope.
        {   let Set(ref set) = *self;

            let Range(mut min_val, mut max_val) = value;
            if min_val > max_val { panic!("First value cannot be greater than the second.") }

            // Loop over set adding old disjoint pieces and supersets back.
            // When partially overlapped, expand value to the union. At the
            // end, insert union after it has been fully expanded.
            for &Range(min, max) in &*set {
                // value overlaps at the beginning.
                if min_val < min && max_val >= min && max_val < max { max_val = max }
                // value overlaps at the end.
                else if min_val > min && min_val <= max && max_val > max { min_val = min }
                // value is entirely contained between min and max. Insert original
                // into new array because new is a subset.
                else if min_val > min && max_val < max {
                    ret.insert(Range(min, max));
                    subset = true;
                }
                // value is a superset to the current so don't add current.
                else if min_val <= min && max_val >= max {}
                // value is disjoint with current so add current.
                else { ret.insert(Range(min, max)); }
            }

            // Insert value only when it's not a subset.
            if !subset { ret.insert(Range(min_val, max_val)); }
        }

        *self = Set(ret);
    }
    pub fn remove(&mut self, value: Range) {
        let mut ret = BTreeSet::new();

        // Borrowing self blocks later modification. Make a new scope to contain it.
        {   let Set(ref set) = *self;

            let Range(min_val, max_val) = value;
            if min_val > max_val { panic!("First value cannot be greater than the second.") }

            // Loop over set inserting whatever doesn't intersect.
            for &Range(min, max) in &*set {
                // value overlaps at the beginning.
                if min_val < min && max_val >= min && max_val < max { ret.insert(Range(max_val.next(), max)); }
                // value overlaps at the end.
                else if min_val > min && min_val <= max && max_val > max { ret.insert(Range(min, min_val.prev())); }
                // value is entirely contained between min and max. Split set
                // into two pieces.
                else if min_val > min && max_val < max {
                    ret.insert(Range(min, min_val.prev()));
                    ret.insert(Range(max_val.next(), max));

                    // Current piece was a superset so value cannot be anywhere else.
                    break;
                // value is a superset to the current so don't add current.
                } else if min_val <= min && max_val >= max {}
                // value is disjoint with current so add current.
                else { ret.insert(Range(min, max)); }
            }
        }

        *self = Set(ret)
    }
    pub fn union(&mut self, value: Self) {
        for x in value.0 { self.insert(x) }
    }
}

#[cfg(test)]
mod test {
    use super::{Range, Set};

    fn generate(vec: Vec<(char, char)>) -> Set {
        let mut set = Set::new();

        for (a, b) in vec {
            set.insert(Range(a, b));
        }

        set
    }
    #[test]
    fn insert_partial_overlap() {
        let set1 = generate(vec![('3', '5'), ('4', '6')]);
        let set2 = generate(vec![('3', '5'), ('1', '4')]);

        let other1 = generate(vec![('3', '6')]);
        let other2 = generate(vec![('1', '5')]);

        assert_eq!(other1, set1);
        assert_eq!(other2, set2);
    }
    #[test]
    fn insert_subset() {
        let set   = generate(vec![('1', '5'), ('2', '3')]);
        let other = generate(vec![('1', '5')]);

        assert_eq!(other, set);
    }
    #[test]
    fn insert_superset() {
        let set   = generate(vec![('3', '5'), ('2', '6')]);
        let other = generate(vec![('2', '6')]);

        assert_eq!(other, set);
    }
    #[test]
    #[should_panic]
    fn panic_on_decreasing_order() {
        generate(vec![('5', '3')]);
    }
    #[test]
    fn set_union() {
        let mut set1 = generate(vec![('1', '4'), ('5', '6')]);
        let set2 =     generate(vec![('0', '5'), ('8', '9')]);

        set1.union(set2);

        let other = generate(vec![('0', '6'), ('8', '9')]);
        assert_eq!(set1, other);
    }
    #[test]
    fn remove_partial_overlap() {
        let mut set1 = generate(vec![('5', '9')]);
        let mut set2 = generate(vec![('2', '6')]);

        set1.remove(Range('3', '6'));
        set2.remove(Range('5', '9'));

        let other1 = generate(vec![('7', '9')]);
        let other2 = generate(vec![('2', '4')]);

        assert_eq!(set1, other1);
        assert_eq!(set2, other2);
    }
    #[test]
    fn remove_subset() {
        let mut set = generate(vec![('1', '9')]);
        set.remove(Range('3', '6'));

        let other = generate(vec![('1', '2'), ('7', '9')]);

        assert_eq!(set, other);
    }
    #[test]
    fn remove_superset() {
        let mut set = generate(vec![('5', '6')]);
        set.remove(Range('3', '8'));

        let other = generate(vec![]);
        assert_eq!(set, other);
    }
    #[test]
    fn remove_disjoint() {
        let mut set = generate(vec![('2', '3')]);
        set.remove(Range('6', '8'));

        let other = generate(vec![('2', '3')]);
        assert_eq!(set, other);
    }
}
<commit_msg>Fix remove when ranges start or end on the same point<commit_after>#![allow(dead_code)]

use std::collections::BTreeSet;
use std::fmt::{self, Display};
use parse::NextPrev;

#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub struct Range(pub char, pub char);

impl fmt::Display for Range {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({}, {})", self.0, self.1)
    }
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Set(BTreeSet<Range>);

impl fmt::Display for Set {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let Set(ref set) = *self;
        let len = BTreeSet::len(set);

        for (count, s) in set.iter().enumerate() {
            if count < len - 1 { try!(write!(f, "{}, ", s)) }
            else { return write!(f, "{}", s) }
        }

        Ok(())
    }
}

impl Set {
    pub fn new() -> Self { Set(BTreeSet::new()) }
    pub fn insert(&mut self, value: Range) {
        let mut ret = BTreeSet::new();
        // value is a complete subset of one of the other ranges.
        let mut subset = false;

        // Borrowing self blocks later operation. Add a new scope.
        {   let Set(ref set) = *self;

            let Range(mut min_val, mut max_val) = value;
            if min_val > max_val { panic!("First value cannot be greater than the second.") }

            // Loop over set adding old disjoint pieces and supersets back.
            // When partially overlapped, expand value to the union. At the
            // end, insert union after it has been fully expanded.
            for &Range(min, max) in &*set {
                // value overlaps at the beginning.
                if min_val < min && max_val >= min && max_val < max { max_val = max }
                // value overlaps at the end.
                else if min_val > min && min_val <= max && max_val > max { min_val = min }
                // value is entirely contained between min and max. Insert original
                // into new array because new is a subset.
                else if min_val > min && max_val < max {
                    ret.insert(Range(min, max));
                    subset = true;
                }
                // value is a superset to the current so don't add current.
                else if min_val <= min && max_val >= max {}
                // value is disjoint with current so add current.
                else { ret.insert(Range(min, max)); }
            }

            // Insert value only when it's not a subset.
            if !subset { ret.insert(Range(min_val, max_val)); }
        }

        *self = Set(ret);
    }
    pub fn remove(&mut self, value: Range) {
        let mut ret = BTreeSet::new();

        // Borrowing self blocks later modification. Make a new scope to contain it.
        {   let Set(ref set) = *self;

            let Range(min_val, max_val) = value;
            if min_val > max_val { panic!("First value cannot be greater than the second.") }

            // Loop over set inserting whatever doesn't intersect.
            for &Range(min, max) in &*set {
                // value overlaps at the beginning.
                if min_val <= min && max_val >= min && max_val < max { ret.insert(Range(max_val.next(), max)); }
                // value overlaps at the end.
                else if min_val > min && min_val <= max && max_val >= max { ret.insert(Range(min, min_val.prev())); }
                // value is entirely contained between min and max. Split set
                // into two pieces.
                else if min_val > min && max_val < max {
                    ret.insert(Range(min, min_val.prev()));
                    ret.insert(Range(max_val.next(), max));

                    // Current piece was a superset so value cannot be anywhere else.
                    break;
                // value is a superset to the current so don't add current.
                } else if min_val <= min && max_val >= max {}
                // value is disjoint with current so add current.
                else { ret.insert(Range(min, max)); }
            }
        }

        *self = Set(ret)
    }
    pub fn union(&mut self, value: Self) {
        for x in value.0 { self.insert(x) }
    }
}

#[cfg(test)]
mod test {
    use super::{Range, Set};

    fn generate(vec: Vec<(char, char)>) -> Set {
        let mut set = Set::new();

        for (a, b) in vec {
            set.insert(Range(a, b));
        }

        set
    }
    #[test]
    fn insert_partial_overlap() {
        let set1 = generate(vec![('3', '5'), ('4', '6')]);
        let set2 = generate(vec![('3', '5'), ('1', '4')]);

        let other1 = generate(vec![('3', '6')]);
        let other2 = generate(vec![('1', '5')]);

        assert_eq!(other1, set1);
        assert_eq!(other2, set2);
    }
    #[test]
    fn insert_subset() {
        let set   = generate(vec![('1', '5'), ('2', '3')]);
        let other = generate(vec![('1', '5')]);

        assert_eq!(other, set);
    }
    #[test]
    fn insert_superset() {
        let set   = generate(vec![('3', '5'), ('2', '6')]);
        let other = generate(vec![('2', '6')]);

        assert_eq!(other, set);
    }
    #[test]
    #[should_panic]
    fn panic_on_decreasing_order() {
        generate(vec![('5', '3')]);
    }
    #[test]
    fn set_union() {
        let mut set1 = generate(vec![('1', '4'), ('5', '6')]);
        let set2 =     generate(vec![('0', '5'), ('8', '9')]);

        set1.union(set2);

        let other = generate(vec![('0', '6'), ('8', '9')]);
        assert_eq!(set1, other);
    }
    #[test]
    fn remove_partial_overlap() {
        let mut set1 = generate(vec![('5', '9')]);
        set1.remove(Range('3', '6')); // beginnings different.

        let mut set2 = generate(vec![('5', '9')]);
        set2.remove(Range('5', '6')); // beginnings same.

        let mut set3 = generate(vec![('2', '6')]);
        set3.remove(Range('5', '9')); // end different.

        let mut set4 = generate(vec![('2', '6')]);
        set4.remove(Range('5', '6')); // end same.

        let other12 = generate(vec![('7', '9')]);
        let other34 = generate(vec![('2', '4')]);

        assert_eq!(set1, other12);
        assert_eq!(set2, other12);
        assert_eq!(set3, other34);
        assert_eq!(set4, other34);
    }
    #[test]
    fn remove_subset() {
        let mut set = generate(vec![('1', '9')]);
        set.remove(Range('3', '6'));

        let other = generate(vec![('1', '2'), ('7', '9')]);

        assert_eq!(set, other);
    }
    #[test]
    fn remove_superset() {
        let mut set = generate(vec![('5', '6')]);
        set.remove(Range('3', '8'));

        let other = generate(vec![]);
        assert_eq!(set, other);
    }
    #[test]
    fn remove_disjoint() {
        let mut set = generate(vec![('2', '3')]);
        set.remove(Range('6', '8'));

        let other = generate(vec![('2', '3')]);
        assert_eq!(set, other);
    }
}
<|endoftext|>