<commit_before>
use std::cell::RefCell;

use ihex::record::Record;
use ihex::writer;

use assembler::data_range;
use assembler::data_range::DataRange;

// MARK: - Public API

/**
 Converts the provided data ranges into a single Intel HEX record. These data ranges
 cannot overlap and still yield a valid I8HEX record. It is the responsibility of
 the caller to ensure this does not happen.
 @param ranges The data ranges to convert to I8HEX format.
 @return The complete I8HEX record (including EOF) of the given data ranges.
 */
pub fn i8hex_representation_of_data_ranges<'a>(ranges: &'a [&'a DataRange]) -> String {
  assert!(data_range::find_overlapping_data_ranges(ranges).len() == 0);

  // All records are collected into a list.
  let mut records = Vec::<Record>::new();

  for range in ranges {

    // The range will be sub-divded into chunks of up to 16 bytes, so sub-address must be tracked.
    let address_for_current_record = RefCell::new(range.address_range().start.as_u16());

    // Sub-divide the range into 16-byte Record::Data objects.
    records.append(
      &mut range
        // Inspect the data in the range.
        .data()
        // As a u8 slice.
        .as_slice()
        // In groups of 16 bytes.
        .chunks(16)
        // Create a tuple of (Record, Length).
        .map(|chunk| (
          Record::Data { offset: *address_for_current_record.borrow(), value: Vec::from(chunk) },
          chunk.len() as u16
        ))
        // Increment the address counter by the number of bytes incorporated into the record.
        .inspect(|&(_, length)| {
          *address_for_current_record.borrow_mut() += length;
        })
        // Discard the length from the tuple.
        .map(|(record, _)| record)
        // Collect the records into a Vec<Record>.
        .collect::<Vec<_>>()
    );

  }

  // All I8HEX files end in an EOF marker.
  records.push(Record::EndOfFile);

  // Obtain the formatted representation of each record and join with newlines for display.
  writer::create_object_file_representation(records.as_slice()).unwrap() + &"\n"
}

// MARK: - Tests

#[cfg(test)]
mod tests {

  use super::i8hex_representation_of_data_ranges;

  use assembler::data_range::DataRange;
  use assembler::u12::*;

  #[test]
  fn test_i8hex_representation_of_data_ranges_no_ranges() {
    // An empty set of data ranges yields just an EOF marker.
    assert_eq!(i8hex_representation_of_data_ranges(&[]), String::from(":00000001FF\n"));
  }

  #[test]
  fn test_i8hex_representation_of_data_ranges_one_range() {
    // Build an average-case I8HEX record.
    let mut data_range = DataRange::new(0x100.as_u12().unwrap());
    data_range.append(&vec![0x21,0x46,0x01,0x36,0x01,0x21,0x47,0x01,0x36,0x00,0x7E,0xFE,0x09,0xD2,0x19,0x01]);
    data_range.append(&vec![0x21,0x46,0x01,0x7E,0x17,0xC2,0x00,0x01,0xFF,0x5F,0x16,0x00,0x21,0x48,0x01,0x19]);
    data_range.append(&vec![0x19,0x4E,0x79,0x23,0x46,0x23,0x96,0x57,0x78,0x23,0x9E,0xDA,0x3F,0x01,0xB2,0xCA]);
    data_range.append(&vec![0x3F,0x01,0x56,0x70,0x2B,0x5E,0x71,0x2B,0x72,0x2B,0x73,0x21,0x46,0x01,0x34,0x21]);

    // Validate the average case yielded the anticipated result.
    let i8hex_rep_average = i8hex_representation_of_data_ranges(&[&data_range]);
    let expected_i8hex_rep_average = String::new() +
      &":10010000214601360121470136007EFE09D2190140\n" +
      &":100110002146017E17C20001FF5F16002148011928\n" +
      &":10012000194E79234623965778239EDA3F01B2CAA7\n" +
      &":100130003F0156702B5E712B722B732146013421C7\n" +
      &":00000001FF\n";
    assert_eq!(i8hex_rep_average, expected_i8hex_rep_average);
  }

  #[test]
  fn test_i8hex_representation_of_data_ranges_adjacent_ranges() {
    // Build a pair of adjacent data ranges.
    let mut range_a = DataRange::new(0x100.as_u12().unwrap());
    range_a.append(&vec![0x21,0x46,0x01,0x36,0x01,0x21,0x47,0x01,0x36,0x00,0x7E,0xFE,0x09,0xD2,0x19,0x01]);
    let mut range_b = DataRange::new(0x110.as_u12().unwrap());
    range_b.append(&vec![0x21,0x46,0x01,0x7E,0x17,0xC2,0x00,0x01,0xFF,0x5F,0x16,0x00,0x21,0x48,0x01,0x19]);

    // Validate the average case yielded the anticipated result.
    let i8hex_rep_adjacent = i8hex_representation_of_data_ranges(&[&range_a, &range_b]);
    let expected_i8hex_rep_adjacent = String::new() +
      &":10010000214601360121470136007EFE09D2190140\n" +
      &":100110002146017E17C20001FF5F16002148011928\n" +
      &":00000001FF\n";
    assert_eq!(i8hex_rep_adjacent, expected_i8hex_rep_adjacent);
  }

  #[test]
  fn test_i8hex_representation_of_data_ranges_disjoint_ranges() {
    // Build an disjoint pair of data ranges.
    let mut range_a = DataRange::new(0x100.as_u12().unwrap());
    range_a.append(&vec![0x21,0x46,0x01,0x36,0x01,0x21,0x47,0x01,0x36,0x00,0x7E,0xFE,0x09,0xD2,0x19,0x01]);
    let mut range_b = DataRange::new(0x130.as_u12().unwrap());
    range_b.append(&vec![0x3F,0x01,0x56,0x70,0x2B,0x5E,0x71,0x2B,0x72,0x2B,0x73,0x21,0x46,0x01,0x34,0x21]);

    // Validate the average case yielded the anticipated result.
    let i8hex_rep_disjoint = i8hex_representation_of_data_ranges(&[&range_a, &range_b]);
    let expected_i8hex_rep_disjoint = String::new() +
      &":10010000214601360121470136007EFE09D2190140\n" +
      &":100130003F0156702B5E712B722B732146013421C7\n" +
      &":00000001FF\n";
    assert_eq!(i8hex_rep_disjoint, expected_i8hex_rep_disjoint);
  }

  #[test]
  fn test_i8hex_representation_of_data_ranges_uneven_ranges() {
    // Build an uneven set of data ranges.
    let mut range_a = DataRange::new(0x100.as_u12().unwrap());
    range_a.append(&vec![0x21,0x46,0x01,0x36,0x01,0x21,0x47,0x01,0x36,0x00,0x7E,0xFE,0x09,0xD2,0x19]);
    let mut range_b = DataRange::new(0x130.as_u12().unwrap());
    range_b.append(&vec![0x3F,0x01,0x56,0x70,0x2B,0x5E,0x71,0x2B,0x72,0x2B,0x73,0x21,0x46,0x01,0x34,0x21,0x22]);
    let mut range_c = DataRange::new(0x200.as_u12().unwrap());
    range_c.append(&vec![0x3F]);

    // Validate the average case yielded the anticipated result.
    let i8hex_rep = i8hex_representation_of_data_ranges(&[&range_a, &range_b, &range_c]);
    let expected_i8hex_rep = String::new() +
      &":0F010000214601360121470136007EFE09D21942\n" +
      &":100130003F0156702B5E712B722B732146013421C7\n" +
      &":01014000229C\n" +
      &":010200003FBE\n" +
      &":00000001FF\n";
    assert_eq!(i8hex_rep, expected_i8hex_rep);
  }

  #[test]
  #[should_panic]
  fn test_i8hex_representation_of_data_ranges_panics_when_overlapping() {
    // Build an overlapping pair of ranges.
    let mut range_a = DataRange::new(0x100.as_u12().unwrap());
    range_a.append(&vec![0x21,0x46,0x01,0x36,0x01,0x21,0x47,0x01,0x36,0x00,0x7E,0xFE,0x09,0xD2,0x19,0x01]);
    let mut range_b = DataRange::new(0x101.as_u12().unwrap());
    range_b.append(&vec![0x3F,0x01,0x56,0x70,0x2B,0x5E,0x71,0x2B,0x72,0x2B,0x73,0x21,0x46,0x01,0x34,0x21]);
    i8hex_representation_of_data_ranges(&[&range_a, &range_b]);
  }

}
<commit_msg>Made i8hex_representation_of_data_ranges() a whole lot more readable.<commit_after>
use std::cell::RefCell;

use ihex::record::Record;
use ihex::writer;

use assembler::data_range;
use assembler::data_range::DataRange;

// MARK: - Public API

/**
 Converts the provided data ranges into a single Intel HEX record. These data ranges
 cannot overlap and still yield a valid I8HEX record. It is the responsibility of
 the caller to ensure this does not happen.
 @param ranges The data ranges to convert to I8HEX format.
 @return The complete I8HEX record (including EOF) of the given data ranges.
 */
pub fn i8hex_representation_of_data_ranges<'a>(ranges: &'a [&'a DataRange]) -> String {
  assert!(data_range::find_overlapping_data_ranges(ranges).len() == 0);

  // All records are collected into a list.
  let mut records = Vec::<Record>::new();

  for range in ranges {

    // The range will be sub-divded into chunks of up to 16 bytes, so sub-address must be tracked.
    let record_address = RefCell::new(range.address_range().start.as_u16());

    // Sub-divide the range into 16-byte Record::Data objects.
    records.append(
      &mut range
        // Inspect the data in the range.
        .data()
        // As a u8 slice.
        .as_slice()
        // In groups of 16 bytes.
        .chunks(16)
        // Create a tuple of (Length, Record).
        .map(|chunk| {
          (chunk.len() as u16, Record::Data { offset: *record_address.borrow(), value: Vec::from(chunk) })
        })
        // Increment the address counter by the number of bytes incorporated into the record.
        .inspect(|&(length, _)| {
          *record_address.borrow_mut() += length;
        })
        // Discard the length from the tuple.
        .map(|(_, record)| record)
        // Collect the records into a Vec<Record>.
        .collect::<Vec<_>>()
    );

  }

  // All I8HEX files end in an EOF marker.
  records.push(Record::EndOfFile);

  // Obtain the formatted representation of each record and join with newlines for display.
  writer::create_object_file_representation(records.as_slice()).unwrap() + &"\n"
}

// MARK: - Tests

#[cfg(test)]
mod tests {

  use super::i8hex_representation_of_data_ranges;

  use assembler::data_range::DataRange;
  use assembler::u12::*;

  #[test]
  fn test_i8hex_representation_of_data_ranges_no_ranges() {
    // An empty set of data ranges yields just an EOF marker.
    assert_eq!(i8hex_representation_of_data_ranges(&[]), String::from(":00000001FF\n"));
  }

  #[test]
  fn test_i8hex_representation_of_data_ranges_one_range() {
    // Build an average-case I8HEX record.
    let mut data_range = DataRange::new(0x100.as_u12().unwrap());
    data_range.append(&vec![0x21,0x46,0x01,0x36,0x01,0x21,0x47,0x01,0x36,0x00,0x7E,0xFE,0x09,0xD2,0x19,0x01]);
    data_range.append(&vec![0x21,0x46,0x01,0x7E,0x17,0xC2,0x00,0x01,0xFF,0x5F,0x16,0x00,0x21,0x48,0x01,0x19]);
    data_range.append(&vec![0x19,0x4E,0x79,0x23,0x46,0x23,0x96,0x57,0x78,0x23,0x9E,0xDA,0x3F,0x01,0xB2,0xCA]);
    data_range.append(&vec![0x3F,0x01,0x56,0x70,0x2B,0x5E,0x71,0x2B,0x72,0x2B,0x73,0x21,0x46,0x01,0x34,0x21]);

    // Validate the average case yielded the anticipated result.
    let i8hex_rep_average = i8hex_representation_of_data_ranges(&[&data_range]);
    let expected_i8hex_rep_average = String::new() +
      &":10010000214601360121470136007EFE09D2190140\n" +
      &":100110002146017E17C20001FF5F16002148011928\n" +
      &":10012000194E79234623965778239EDA3F01B2CAA7\n" +
      &":100130003F0156702B5E712B722B732146013421C7\n" +
      &":00000001FF\n";
    assert_eq!(i8hex_rep_average, expected_i8hex_rep_average);
  }

  #[test]
  fn test_i8hex_representation_of_data_ranges_adjacent_ranges() {
    // Build a pair of adjacent data ranges.
    let mut range_a = DataRange::new(0x100.as_u12().unwrap());
    range_a.append(&vec![0x21,0x46,0x01,0x36,0x01,0x21,0x47,0x01,0x36,0x00,0x7E,0xFE,0x09,0xD2,0x19,0x01]);
    let mut range_b = DataRange::new(0x110.as_u12().unwrap());
    range_b.append(&vec![0x21,0x46,0x01,0x7E,0x17,0xC2,0x00,0x01,0xFF,0x5F,0x16,0x00,0x21,0x48,0x01,0x19]);

    // Validate the average case yielded the anticipated result.
    let i8hex_rep_adjacent = i8hex_representation_of_data_ranges(&[&range_a, &range_b]);
    let expected_i8hex_rep_adjacent = String::new() +
      &":10010000214601360121470136007EFE09D2190140\n" +
      &":100110002146017E17C20001FF5F16002148011928\n" +
      &":00000001FF\n";
    assert_eq!(i8hex_rep_adjacent, expected_i8hex_rep_adjacent);
  }

  #[test]
  fn test_i8hex_representation_of_data_ranges_disjoint_ranges() {
    // Build an disjoint pair of data ranges.
    let mut range_a = DataRange::new(0x100.as_u12().unwrap());
    range_a.append(&vec![0x21,0x46,0x01,0x36,0x01,0x21,0x47,0x01,0x36,0x00,0x7E,0xFE,0x09,0xD2,0x19,0x01]);
    let mut range_b = DataRange::new(0x130.as_u12().unwrap());
    range_b.append(&vec![0x3F,0x01,0x56,0x70,0x2B,0x5E,0x71,0x2B,0x72,0x2B,0x73,0x21,0x46,0x01,0x34,0x21]);

    // Validate the average case yielded the anticipated result.
    let i8hex_rep_disjoint = i8hex_representation_of_data_ranges(&[&range_a, &range_b]);
    let expected_i8hex_rep_disjoint = String::new() +
      &":10010000214601360121470136007EFE09D2190140\n" +
      &":100130003F0156702B5E712B722B732146013421C7\n" +
      &":00000001FF\n";
    assert_eq!(i8hex_rep_disjoint, expected_i8hex_rep_disjoint);
  }

  #[test]
  fn test_i8hex_representation_of_data_ranges_uneven_ranges() {
    // Build an uneven set of data ranges.
    let mut range_a = DataRange::new(0x100.as_u12().unwrap());
    range_a.append(&vec![0x21,0x46,0x01,0x36,0x01,0x21,0x47,0x01,0x36,0x00,0x7E,0xFE,0x09,0xD2,0x19]);
    let mut range_b = DataRange::new(0x130.as_u12().unwrap());
    range_b.append(&vec![0x3F,0x01,0x56,0x70,0x2B,0x5E,0x71,0x2B,0x72,0x2B,0x73,0x21,0x46,0x01,0x34,0x21,0x22]);
    let mut range_c = DataRange::new(0x200.as_u12().unwrap());
    range_c.append(&vec![0x3F]);

    // Validate the average case yielded the anticipated result.
    let i8hex_rep = i8hex_representation_of_data_ranges(&[&range_a, &range_b, &range_c]);
    let expected_i8hex_rep = String::new() +
      &":0F010000214601360121470136007EFE09D21942\n" +
      &":100130003F0156702B5E712B722B732146013421C7\n" +
      &":01014000229C\n" +
      &":010200003FBE\n" +
      &":00000001FF\n";
    assert_eq!(i8hex_rep, expected_i8hex_rep);
  }

  #[test]
  #[should_panic]
  fn test_i8hex_representation_of_data_ranges_panics_when_overlapping() {
    // Build an overlapping pair of ranges.
    let mut range_a = DataRange::new(0x100.as_u12().unwrap());
    range_a.append(&vec![0x21,0x46,0x01,0x36,0x01,0x21,0x47,0x01,0x36,0x00,0x7E,0xFE,0x09,0xD2,0x19,0x01]);
    let mut range_b = DataRange::new(0x101.as_u12().unwrap());
    range_b.append(&vec![0x3F,0x01,0x56,0x70,0x2B,0x5E,0x71,0x2B,0x72,0x2B,0x73,0x21,0x46,0x01,0x34,0x21]);
    i8hex_representation_of_data_ranges(&[&range_a, &range_b]);
  }

}
<|endoftext|>


<commit_before>use crate::protobuf_ident::ProtobufIdent;
use crate::ProtobufRelativePath;
use std::fmt;

#[derive(Clone, Eq, PartialEq, Debug, Hash)]
pub struct ProtobufAbsolutePath {
    pub path: String,
}

impl ProtobufAbsolutePath {
    pub fn root() -> ProtobufAbsolutePath {
        ProtobufAbsolutePath::new(String::new())
    }

    pub fn new(path: String) -> ProtobufAbsolutePath {
        assert!(path.is_empty() || path.starts_with("."), path);
        assert!(!path.ends_with("."), path);
        ProtobufAbsolutePath { path }
    }

    pub fn is_empty(&self) -> bool {
        self.path.is_empty()
    }

    pub fn from_package_path(path: Option<&str>) -> ProtobufAbsolutePath {
        match path {
            None => ProtobufAbsolutePath::root(),
            Some(path) => ProtobufAbsolutePath::from_path_without_dot(path),
        }
    }

    pub fn from_path_without_dot(path: &str) -> ProtobufAbsolutePath {
        assert!(!path.is_empty());
        assert!(!path.starts_with("."));
        assert!(!path.ends_with("."));
        ProtobufAbsolutePath::new(format!(".{}", path))
    }

    pub fn from_path_maybe_dot(path: &str) -> ProtobufAbsolutePath {
        if path.starts_with(".") {
            ProtobufAbsolutePath::new(path.to_owned())
        } else {
            ProtobufAbsolutePath::from_path_without_dot(path)
        }
    }

    pub fn push_simple(&mut self, simple: ProtobufIdent) {
        self.path.push('.');
        self.path.push_str(simple.get());
    }

    pub fn push_relative(&mut self, relative: &ProtobufRelativePath) {
        if !relative.is_empty() {
            self.path.push('.');
            self.path.push_str(&relative.path);
        }
    }

    pub fn remove_prefix(&self, prefix: &ProtobufAbsolutePath) -> Option<ProtobufRelativePath> {
        if self.path.starts_with(&prefix.path) {
            let rem = &self.path[prefix.path.len()..];
            if rem.is_empty() {
                return Some(ProtobufRelativePath::empty());
            }
            if rem.starts_with('.') {
                return Some(ProtobufRelativePath::new(rem[1..].to_owned()));
            }
        }
        None
    }

    fn parent(&self) -> Option<ProtobufAbsolutePath> {
        match self.path.rfind('.') {
            Some(pos) => Some(ProtobufAbsolutePath::new(self.path[..pos].to_owned())),
            None => {
                if self.path.is_empty() {
                    None
                } else {
                    Some(ProtobufAbsolutePath::root())
                }
            }
        }
    }

    pub fn self_and_parents(&self) -> Vec<ProtobufAbsolutePath> {
        let mut tmp = self.clone();

        let mut r = Vec::new();

        r.push(self.clone());

        while let Some(parent) = tmp.parent() {
            r.push(parent.clone());
            tmp = parent;
        }

        r
    }
}

impl From<&'_ str> for ProtobufAbsolutePath {
    fn from(s: &str) -> Self {
        ProtobufAbsolutePath::new(s.to_owned())
    }
}

impl From<String> for ProtobufAbsolutePath {
    fn from(s: String) -> Self {
        ProtobufAbsolutePath::new(s)
    }
}

impl fmt::Display for ProtobufAbsolutePath {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.path, f)
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn absolute_path_push_simple() {
        let mut foo = ProtobufAbsolutePath::new(".foo".to_owned());
        foo.push_simple(ProtobufIdent::from("bar"));
        assert_eq!(ProtobufAbsolutePath::new(".foo.bar".to_owned()), foo);

        let mut foo = ProtobufAbsolutePath::root();
        foo.push_simple(ProtobufIdent::from("bar"));
        assert_eq!(ProtobufAbsolutePath::new(".bar".to_owned()), foo);
    }

    #[test]
    fn absolute_path_remove_prefix() {
        assert_eq!(
            Some(ProtobufRelativePath::empty()),
            ProtobufAbsolutePath::new(".foo".to_owned())
                .remove_prefix(&ProtobufAbsolutePath::new(".foo".to_owned()))
        );
        assert_eq!(
            Some(ProtobufRelativePath::new("bar".to_owned())),
            ProtobufAbsolutePath::new(".foo.bar".to_owned())
                .remove_prefix(&ProtobufAbsolutePath::new(".foo".to_owned()))
        );
        assert_eq!(
            Some(ProtobufRelativePath::new("baz.qux".to_owned())),
            ProtobufAbsolutePath::new(".foo.bar.baz.qux".to_owned())
                .remove_prefix(&ProtobufAbsolutePath::new(".foo.bar".to_owned()))
        );
        assert_eq!(
            None,
            ProtobufAbsolutePath::new(".foo.barbaz".to_owned())
                .remove_prefix(&ProtobufAbsolutePath::new(".foo.bar".to_owned()))
        );
    }
}
<commit_msg>Test for ProtobufAbsPath::self_and_parents<commit_after>use crate::protobuf_ident::ProtobufIdent;
use crate::ProtobufRelativePath;
use std::fmt;

#[derive(Clone, Eq, PartialEq, Debug, Hash)]
pub struct ProtobufAbsolutePath {
    pub path: String,
}

impl ProtobufAbsolutePath {
    pub fn root() -> ProtobufAbsolutePath {
        ProtobufAbsolutePath::new(String::new())
    }

    pub fn new(path: String) -> ProtobufAbsolutePath {
        assert!(path.is_empty() || path.starts_with("."), path);
        assert!(!path.ends_with("."), path);
        ProtobufAbsolutePath { path }
    }

    pub fn is_empty(&self) -> bool {
        self.path.is_empty()
    }

    pub fn from_package_path(path: Option<&str>) -> ProtobufAbsolutePath {
        match path {
            None => ProtobufAbsolutePath::root(),
            Some(path) => ProtobufAbsolutePath::from_path_without_dot(path),
        }
    }

    pub fn from_path_without_dot(path: &str) -> ProtobufAbsolutePath {
        assert!(!path.is_empty());
        assert!(!path.starts_with("."));
        assert!(!path.ends_with("."));
        ProtobufAbsolutePath::new(format!(".{}", path))
    }

    pub fn from_path_maybe_dot(path: &str) -> ProtobufAbsolutePath {
        if path.starts_with(".") {
            ProtobufAbsolutePath::new(path.to_owned())
        } else {
            ProtobufAbsolutePath::from_path_without_dot(path)
        }
    }

    pub fn push_simple(&mut self, simple: ProtobufIdent) {
        self.path.push('.');
        self.path.push_str(simple.get());
    }

    pub fn push_relative(&mut self, relative: &ProtobufRelativePath) {
        if !relative.is_empty() {
            self.path.push('.');
            self.path.push_str(&relative.path);
        }
    }

    pub fn remove_prefix(&self, prefix: &ProtobufAbsolutePath) -> Option<ProtobufRelativePath> {
        if self.path.starts_with(&prefix.path) {
            let rem = &self.path[prefix.path.len()..];
            if rem.is_empty() {
                return Some(ProtobufRelativePath::empty());
            }
            if rem.starts_with('.') {
                return Some(ProtobufRelativePath::new(rem[1..].to_owned()));
            }
        }
        None
    }

    fn parent(&self) -> Option<ProtobufAbsolutePath> {
        match self.path.rfind('.') {
            Some(pos) => Some(ProtobufAbsolutePath::new(self.path[..pos].to_owned())),
            None => {
                if self.path.is_empty() {
                    None
                } else {
                    Some(ProtobufAbsolutePath::root())
                }
            }
        }
    }

    pub fn self_and_parents(&self) -> Vec<ProtobufAbsolutePath> {
        let mut tmp = self.clone();

        let mut r = Vec::new();

        r.push(self.clone());

        while let Some(parent) = tmp.parent() {
            r.push(parent.clone());
            tmp = parent;
        }

        r
    }
}

impl From<&'_ str> for ProtobufAbsolutePath {
    fn from(s: &str) -> Self {
        ProtobufAbsolutePath::new(s.to_owned())
    }
}

impl From<String> for ProtobufAbsolutePath {
    fn from(s: String) -> Self {
        ProtobufAbsolutePath::new(s)
    }
}

impl fmt::Display for ProtobufAbsolutePath {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.path, f)
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn absolute_path_push_simple() {
        let mut foo = ProtobufAbsolutePath::new(".foo".to_owned());
        foo.push_simple(ProtobufIdent::from("bar"));
        assert_eq!(ProtobufAbsolutePath::new(".foo.bar".to_owned()), foo);

        let mut foo = ProtobufAbsolutePath::root();
        foo.push_simple(ProtobufIdent::from("bar"));
        assert_eq!(ProtobufAbsolutePath::new(".bar".to_owned()), foo);
    }

    #[test]
    fn absolute_path_remove_prefix() {
        assert_eq!(
            Some(ProtobufRelativePath::empty()),
            ProtobufAbsolutePath::new(".foo".to_owned())
                .remove_prefix(&ProtobufAbsolutePath::new(".foo".to_owned()))
        );
        assert_eq!(
            Some(ProtobufRelativePath::new("bar".to_owned())),
            ProtobufAbsolutePath::new(".foo.bar".to_owned())
                .remove_prefix(&ProtobufAbsolutePath::new(".foo".to_owned()))
        );
        assert_eq!(
            Some(ProtobufRelativePath::new("baz.qux".to_owned())),
            ProtobufAbsolutePath::new(".foo.bar.baz.qux".to_owned())
                .remove_prefix(&ProtobufAbsolutePath::new(".foo.bar".to_owned()))
        );
        assert_eq!(
            None,
            ProtobufAbsolutePath::new(".foo.barbaz".to_owned())
                .remove_prefix(&ProtobufAbsolutePath::new(".foo.bar".to_owned()))
        );
    }

    #[test]
    fn self_and_parents() {
        assert_eq!(
            vec![
                ProtobufAbsolutePath::new(".ab.cde.fghi".to_owned()),
                ProtobufAbsolutePath::new(".ab.cde".to_owned()),
                ProtobufAbsolutePath::new(".ab".to_owned()),
                ProtobufAbsolutePath::root(),
            ],
            ProtobufAbsolutePath::new(".ab.cde.fghi".to_owned()).self_and_parents()
        );
    }
}
<|endoftext|>


<commit_before>extern crate pest;

use std::io::{self, Write};
use std::rc::Rc;

use pest::inputs::{Input, Position, StringInput};
use pest::iterators::Pairs;
use pest::{Error, Parser, ParserState, state};

#[allow(non_camel_case_types)]
#[allow(dead_code)]
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
enum Rule {
    expr,
    paren
}

struct ParenParser;

impl Parser<Rule> for ParenParser {
    fn parse<I: Input>(rule: Rule, input: Rc<I>) -> Result<Pairs<Rule, I>, Error<Rule, I>> {
        fn expr<I: Input>(
            pos: Position<I>,
            state: &mut ParserState<Rule, I>
        ) -> Result<Position<I>, Position<I>> {
            state.sequence(move |state| {
                pos.sequence(|p| {
                    p.repeat(|p| {
                        paren(p, state)
                    }).and_then(|p| {
                        p.at_end()
                    })
                })
            })
        }

        fn paren<I: Input>(
            pos: Position<I>,
            state: &mut ParserState<Rule, I>
        ) -> Result<Position<I>, Position<I>> {
            state.rule(Rule::paren, pos, |state, pos| {
                state.sequence(move |state| {
                    pos.sequence(|p| {
                        p.match_string("(").and_then(|p| {
                            p.optional(|p| {
                                state.sequence(move |state| {
                                    p.sequence(|p| {
                                        state.lookahead(true, move |_| {
                                            p.lookahead(true, |p| {
                                                p.match_string("(")
                                            })
                                        }).and_then(|p| {
                                            p.repeat(|p| {
                                                paren(p, state)
                                            })
                                        })
                                    })
                                })
                            })
                        }).and_then(|p| {
                            p.match_string(")")
                        })
                    })
                })
            })
        }

        state(input, move |mut state, pos| {
            match rule {
                Rule::expr => expr(pos, &mut state),
                Rule::paren => paren(pos, &mut state)
            }
        })
    }
}

#[derive(Debug)]
struct Paren(Vec<Paren>);

fn expr<I: Input>(pairs: Pairs<Rule, I>) -> Vec<Paren> {
    pairs.filter(|p| p.rule() == Rule::paren).map(|p| Paren(expr(p.consume()))).collect()
}

fn main() {
    loop {
        let mut line = String::new();

        print!("> ");
        io::stdout().flush().unwrap();

        io::stdin().read_line(&mut line).unwrap();
        line.pop();

        let input = Rc::new(StringInput::new(line));

        match ParenParser::parse(Rule::expr, input) {
            Ok(pairs) => println!("{:?}", expr(pairs)),
            Err(e) => println!("\n{}", e)
        };
    }
}
<commit_msg>Added paren_end to example.<commit_after>extern crate pest;

use std::io::{self, Write};
use std::rc::Rc;

use pest::inputs::{Input, Position, StringInput};
use pest::iterators::Pairs;
use pest::{Error, Parser, ParserState, state};

#[allow(non_camel_case_types)]
#[allow(dead_code)]
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
enum Rule {
    expr,
    paren,
    paren_end
}

struct ParenParser;

impl Parser<Rule> for ParenParser {
    fn parse<I: Input>(rule: Rule, input: Rc<I>) -> Result<Pairs<Rule, I>, Error<Rule, I>> {
        fn expr<I: Input>(
            pos: Position<I>,
            state: &mut ParserState<Rule, I>
        ) -> Result<Position<I>, Position<I>> {
            state.sequence(move |state| {
                pos.sequence(|p| {
                    p.repeat(|p| {
                        paren(p, state)
                    }).and_then(|p| {
                        p.at_end()
                    })
                })
            })
        }

        fn paren<I: Input>(
            pos: Position<I>,
            state: &mut ParserState<Rule, I>
        ) -> Result<Position<I>, Position<I>> {
            state.rule(Rule::paren, pos, |state, pos| {
                state.sequence(move |state| {
                    pos.sequence(|p| {
                        p.match_string("(").and_then(|p| {
                            p.optional(|p| {
                                state.sequence(move |state| {
                                    p.sequence(|p| {
                                        state.lookahead(true, move |_| {
                                            p.lookahead(true, |p| {
                                                p.match_string("(")
                                            })
                                        }).and_then(|p| {
                                            p.repeat(|p| {
                                                paren(p, state)
                                            })
                                        })
                                    })
                                })
                            })
                        }).and_then(|p| {
                            state.rule(Rule::paren_end, p, |state, pos| {
                                pos.match_string(")")
                            })
                        })
                    })
                })
            })
        }

        state(input, move |mut state, pos| {
            match rule {
                Rule::expr => expr(pos, &mut state),
                Rule::paren => paren(pos, &mut state),
                _ => unreachable!()
            }
        })
    }
}

#[derive(Debug)]
struct Paren(Vec<Paren>);

fn expr<I: Input>(pairs: Pairs<Rule, I>) -> Vec<Paren> {
    pairs.filter(|p| p.rule() == Rule::paren).map(|p| Paren(expr(p.consume()))).collect()
}

fn main() {
    loop {
        let mut line = String::new();

        print!("> ");
        io::stdout().flush().unwrap();

        io::stdin().read_line(&mut line).unwrap();
        line.pop();

        let input = Rc::new(StringInput::new(line));

        match ParenParser::parse(Rule::expr, input) {
            Ok(pairs) => println!("{:?}", expr(pairs)),
            Err(e) => println!("\n{}", e)
        };
    }
}
<|endoftext|>


<commit_before>extern crate rand;
extern crate time;
extern crate timely;
extern crate differential_dataflow;

use std::rc::Rc;
use std::cell::RefCell;

use std::fs::File;
use std::io::{BufRead, BufReader};

use timely::*;
use timely::dataflow::*;
use timely::dataflow::operators::*;
use timely::drain::DrainExt;

use timely::progress::timestamp::RootTimestamp;
use timely::dataflow::channels::pact::Pipeline;

use differential_dataflow::operators::*;

fn main() {

    let parts_pattern = std::env::args().nth(2).unwrap();
    let items_pattern = std::env::args().nth(3).unwrap();
    let delimiter = std::env::args().nth(4).unwrap();

    timely::execute_from_args(std::env::args().skip(4), move |computation| {

        let comm_index = computation.index();
        let comm_peers = computation.peers();

        let mut start = time::precise_time_s();

        let epoch = Rc::new(RefCell::new(0u64));
        let clone = epoch.clone();

        // form the TPCH17-like query
        let (mut parts, mut items) = computation.scoped(|builder| {

            let (part_input, parts) = builder.new_input::<((u32, String, String), i32)>();
            let (item_input, items) = builder.new_input::<((u32, u32, u64), i32)>();

            // filter parts by brand and container
            let parts = parts.filter(|x| (x.0).1 == "Brand#23" && (x.0).2 == "MED BOX")
                             .map(|((key, _, _), wgt)| (key, wgt));

            // restrict lineitems to those of the relevant part
            let items = items.join_by_u(&parts, |x| (x.0, (x.1,x.2)), |y| (y,()), |k,x,_| (*k,x.0,x.1));

            // compute the average quantities
            let average = items.group_by_u(|(x,y,_)| (x,y), |k,v| (*k,*v), |_,s,t| {
                let mut sum = 0;
                let mut cnt = 0;
                for (&val,wgt) in s {
                    cnt += wgt;
                    sum += val;
                }
                t.push((sum / cnt as u32, 1));
            });

            // join items against their averages, filter by quantity, remove filter coordinate
            items.join_by_u(&average, |x| (x.0, (x.1, x.2)), |y| y, |k, x, f| (*k, x.0, x.1, *f))
                 .filter(|&((_, q, _, avg),_)| q < avg / 5)
                 .map(|((key,_,price,_), wgt)| ((key,price), wgt))
                 .unary_notify::<u32, _, _>(Pipeline, "Subscribe", vec![RootTimestamp::new(0)], move |i,_,n| {
                     while let Some(_) = i.next() { }
                     for (time,_) in n.next() {
                         *clone.borrow_mut() = time.inner + 1;
                         if n.frontier(0).len() > 0 {
                             n.notify_at(&RootTimestamp::new(*clone.borrow()));
                         }
                     }
                 })
                 ;

            (part_input, item_input)
        });

        // read the parts input file
        if let Ok(parts_file) = File::open(format!("{}-{}-{}", parts_pattern, comm_index, comm_peers)) {
            let parts_reader = BufReader::new(parts_file);
            for (index, line) in parts_reader.lines().enumerate() {
                if index % comm_peers == comm_index {
                    let text = line.ok().expect("read error");
                    let mut fields = text.split(&delimiter);
                    let part_id = fields.next().unwrap().parse::<u32>().unwrap();
                    fields.next();
                    fields.next();
                    let brand = fields.next().unwrap().to_owned();
                    fields.next();
                    fields.next();
                    let container = fields.next().unwrap().to_owned();
                    parts.send(((part_id, brand, container), 1));
                }
            }

            computation.step();
        }
        else { println!("worker {}: did not find input {}-{}-{}", computation.index(), parts_pattern, comm_index, comm_peers); }

        // read the lineitems input file
        let mut items_buffer = Vec::new();
        if let Ok(items_file) = File::open(format!("{}-{}-{}", items_pattern, comm_index, comm_peers)) {
            let items_reader =  BufReader::new(items_file);
            for (index, line) in items_reader.lines().enumerate() {
                if index % comm_peers == comm_index {
                    let text = line.ok().expect("read error");
                    let mut fields = text.split(&delimiter);
                    fields.next();
                    let item_id = fields.next().unwrap().parse::<u32>().unwrap();
                    fields.next();
                    fields.next();
                    let quantity = fields.next().unwrap().parse::<u32>().unwrap();
                    let extended_price = fields.next().unwrap().parse::<f64>().unwrap() as u64;
                    items_buffer.push(((item_id, quantity, extended_price), 1i32));
                }
            }
        }
        else { println!("worker {}: did not find input {}-{}-{}", comm_index, items_pattern, comm_index, comm_peers); }

        println!("data loaded at {}", time::precise_time_s() - start);
        start = time::precise_time_s();

        parts.close();
        let item_count = items_buffer.len();

        for (index, item) in items_buffer.drain_temp().enumerate() {
            items.send(item);
            items.advance_to(index as u64 + 1);
            while *epoch.borrow() <= index as u64 {
                computation.step();
            }
        }

        // items.send_at(0, items_buffer.drain_temp());

        items.close();

        while computation.step() { }
        computation.step(); // shut down

        println!("computation finished at {}", time::precise_time_s() - start);
        println!("rate: {}", (item_count as f64) / (time::precise_time_s() - start));
    });
}
<commit_msg>tpch17 bug fix<commit_after>extern crate rand;
extern crate time;
extern crate timely;
extern crate differential_dataflow;

use std::rc::Rc;
use std::cell::RefCell;

use std::fs::File;
use std::io::{BufRead, BufReader};

use timely::*;
use timely::dataflow::*;
use timely::dataflow::operators::*;
use timely::drain::DrainExt;

use timely::progress::timestamp::RootTimestamp;
use timely::dataflow::channels::pact::Pipeline;

use differential_dataflow::operators::group::GroupBy;
use differential_dataflow::operators::join::JoinBy;

fn main() {

    let parts_pattern = std::env::args().nth(2).unwrap();
    let items_pattern = std::env::args().nth(3).unwrap();
    let delimiter = std::env::args().nth(4).unwrap();

    timely::execute_from_args(std::env::args().skip(4), move |computation| {

        let comm_index = computation.index();
        let comm_peers = computation.peers();

        let mut start = time::precise_time_s();

        let epoch = Rc::new(RefCell::new(0u64));
        let clone = epoch.clone();

        // form the TPCH17-like query
        let (mut parts, mut items) = computation.scoped(|builder| {

            let (part_input, parts) = builder.new_input::<((u32, String, String), i32)>();
            let (item_input, items) = builder.new_input::<((u32, u32, u64), i32)>();

            // filter parts by brand and container
            let parts = parts.filter(|x| (x.0).1 == "Brand#23" && (x.0).2 == "MED BOX")
                             .map(|((key, _, _), wgt)| (key, wgt));

            // restrict lineitems to those of the relevant part
            let items = items.join_by_u(&parts, |x| (x.0, (x.1,x.2)), |y| (y,()), |k,x,_| (*k,x.0,x.1));

            // compute the average quantities
            let average = items.group_by_u(|(x,y,_)| (x,y), |k,v| (*k,*v), |_,s,t| {
                let mut sum = 0;
                let mut cnt = 0;
                for (&val,wgt) in s {
                    cnt += wgt;
                    sum += val;
                }
                t.push((sum / cnt as u32, 1));
            });

            // join items against their averages, filter by quantity, remove filter coordinate
            items.join_by_u(&average, |x| (x.0, (x.1, x.2)), |y| y, |k, x, f| (*k, x.0, x.1, *f))
                 .filter(|&((_, q, _, avg),_)| q < avg / 5)
                 .map(|((key,_,price,_), wgt)| ((key,price), wgt))
                 .unary_notify::<u32, _, _>(Pipeline, "Subscribe", vec![RootTimestamp::new(0)], move |i,_,n| {
                     while let Some(_) = i.next() { }
                     for (time,_) in n.next() {
                         *clone.borrow_mut() = time.inner + 1;
                         if n.frontier(0).len() > 0 {
                             n.notify_at(&RootTimestamp::new(*clone.borrow()));
                         }
                     }
                 })
                 ;

            (part_input, item_input)
        });

        // read the parts input file
        if let Ok(parts_file) = File::open(format!("{}-{}-{}", parts_pattern, comm_index, comm_peers)) {
            let parts_reader = BufReader::new(parts_file);
            for (index, line) in parts_reader.lines().enumerate() {
                if index % comm_peers == comm_index {
                    let text = line.ok().expect("read error");
                    let mut fields = text.split(&delimiter);
                    let part_id = fields.next().unwrap().parse::<u32>().unwrap();
                    fields.next();
                    fields.next();
                    let brand = fields.next().unwrap().to_owned();
                    fields.next();
                    fields.next();
                    let container = fields.next().unwrap().to_owned();
                    parts.send(((part_id, brand, container), 1));
                }
            }

            computation.step();
        }
        else { println!("worker {}: did not find input {}-{}-{}", computation.index(), parts_pattern, comm_index, comm_peers); }

        // read the lineitems input file
        let mut items_buffer = Vec::new();
        if let Ok(items_file) = File::open(format!("{}-{}-{}", items_pattern, comm_index, comm_peers)) {
            let items_reader =  BufReader::new(items_file);
            for (index, line) in items_reader.lines().enumerate() {
                if index % comm_peers == comm_index {
                    let text = line.ok().expect("read error");
                    let mut fields = text.split(&delimiter);
                    fields.next();
                    let item_id = fields.next().unwrap().parse::<u32>().unwrap();
                    fields.next();
                    fields.next();
                    let quantity = fields.next().unwrap().parse::<u32>().unwrap();
                    let extended_price = fields.next().unwrap().parse::<f64>().unwrap() as u64;
                    items_buffer.push(((item_id, quantity, extended_price), 1i32));
                }
            }
        }
        else { println!("worker {}: did not find input {}-{}-{}", comm_index, items_pattern, comm_index, comm_peers); }

        println!("data loaded at {}", time::precise_time_s() - start);
        start = time::precise_time_s();

        parts.close();
        let item_count = items_buffer.len();

        for (index, item) in items_buffer.drain_temp().enumerate() {
            items.send(item);
            items.advance_to(index as u64 + 1);
            while *epoch.borrow() <= index as u64 {
                computation.step();
            }
        }

        // items.send_at(0, items_buffer.drain_temp());

        items.close();

        while computation.step() { }
        computation.step(); // shut down

        println!("computation finished at {}", time::precise_time_s() - start);
        println!("rate: {}", (item_count as f64) / (time::precise_time_s() - start));
    });
}
<|endoftext|>


<commit_before>use prolog::ast::*;
use prolog::heap_iter::*;

use std::cell::Cell;
use std::rc::Rc;

#[derive(Clone)]
pub enum TokenOrRedirect {
    Atom(ClauseName),
    Redirect,
    Open,
    Close,
    Comma,
    OpenList(Rc<Cell<bool>>),
    CloseList(Rc<Cell<bool>>),
    HeadTailSeparator,
    Space
}

pub trait HeapCellValueFormatter {
    // this function belongs to the display predicate formatter, which it uses
    // to format all clauses.
    fn format_struct(&self, arity: usize, name: ClauseName, state_stack: &mut Vec<TokenOrRedirect>)
    {
        state_stack.push(TokenOrRedirect::Close);

        for _ in 0 .. arity {
            state_stack.push(TokenOrRedirect::Redirect);
            state_stack.push(TokenOrRedirect::Comma);
        }

        state_stack.pop();
        state_stack.push(TokenOrRedirect::Open);

        state_stack.push(TokenOrRedirect::Atom(name));
    }

    // this can be overloaded to handle special cases, falling back on the default of
    // format_struct when convenient.
    fn format_clause(&self, usize, ClauseType, &mut Vec<TokenOrRedirect>);
}

pub trait HeapCellValueOutputter {
    type Output;

    fn new() -> Self;
    fn append(&mut self, &str);
    fn begin_new_var(&mut self);
    fn result(self) -> Self::Output;
    fn ends_with(&self, &str) -> bool;
    fn len(&self) -> usize;
    fn truncate(&mut self, usize);
}

pub struct PrinterOutputter {
    contents: String
}

impl HeapCellValueOutputter for PrinterOutputter {
    type Output = String;

    fn new() -> Self {
        PrinterOutputter { contents: String::new() }
    }

    fn append(&mut self, contents: &str) {
        self.contents += contents;
    }

    fn begin_new_var(&mut self) {
        if self.contents.len() != 0 {
            self.contents += ", ";
        }
    }

    fn result(self) -> Self::Output {
        self.contents
    }

    fn ends_with(&self, s: &str) -> bool {
        self.contents.ends_with(s)
    }

    fn len(&self) -> usize {
        self.contents.len()
    }

    fn truncate(&mut self, len: usize) {
        self.contents.truncate(len);
    }
}

// the 'classic' display corresponding to the display predicate.
pub struct DisplayFormatter {}

impl HeapCellValueFormatter for DisplayFormatter {
    fn format_clause(&self, arity: usize, ct: ClauseType, state_stack: &mut Vec<TokenOrRedirect>)
    {
        if ct.fixity().is_some() {
            let mut new_name = String::from("'");
            new_name += ct.name().as_str();
            new_name += "'";

            self.format_struct(arity, ct.name(), state_stack);
        } else {
            self.format_struct(arity, ct.name(), state_stack);
        }
    }
}

pub struct TermFormatter {}

impl HeapCellValueFormatter for TermFormatter {
    fn format_clause(&self, arity: usize, ct: ClauseType, state_stack: &mut Vec<TokenOrRedirect>)
    {
        if let Some(fixity) = ct.fixity() {
            match fixity {
                Fixity::Post => {
                    state_stack.push(TokenOrRedirect::Atom(ct.name()));
                    state_stack.push(TokenOrRedirect::Space);
                    state_stack.push(TokenOrRedirect::Redirect);
                },
                Fixity::Pre => {
                    state_stack.push(TokenOrRedirect::Redirect);
                    state_stack.push(TokenOrRedirect::Space);
                    state_stack.push(TokenOrRedirect::Atom(ct.name()));
                },
                Fixity::In => {
                    state_stack.push(TokenOrRedirect::Redirect);
                    state_stack.push(TokenOrRedirect::Space);
                    state_stack.push(TokenOrRedirect::Atom(ct.name()));
                    state_stack.push(TokenOrRedirect::Space);
                    state_stack.push(TokenOrRedirect::Redirect);
                }
            }
        } else {
            self.format_struct(arity, ct.name(), state_stack);
        }
    }
}

pub struct HeapCellPrinter<'a, Formatter, Outputter> {
    formatter:   Formatter,
    outputter:   Outputter,
    iter:        HeapCellPreOrderIterator<'a>,
    state_stack: Vec<TokenOrRedirect>
}

impl<'a, Formatter: HeapCellValueFormatter, Outputter: HeapCellValueOutputter>
    HeapCellPrinter<'a, Formatter, Outputter>
{
    pub fn new(iter: HeapCellPreOrderIterator<'a>, formatter: Formatter, outputter: Outputter)
               -> Self
    {
        HeapCellPrinter { formatter, outputter, iter, state_stack: vec![] }
    }

    fn handle_heap_term(&mut self, heap_val: HeapCellValue) {
        match heap_val {
            HeapCellValue::NamedStr(arity, name, fixity) => {
                let ct = ClauseType::from(name, arity, fixity);
                self.formatter.format_clause(arity, ct, &mut self.state_stack)
            },
            HeapCellValue::Addr(Addr::Con(Constant::EmptyList)) =>
                if !self.at_cdr("") {
                    self.outputter.append("[]");
                },
            HeapCellValue::Addr(Addr::Con(c)) =>
                self.outputter.append(format!("{}", c).as_str()),
            HeapCellValue::Addr(Addr::Lis(_)) => {
                let cell = Rc::new(Cell::new(true));

                self.state_stack.push(TokenOrRedirect::CloseList(cell.clone()));

                self.state_stack.push(TokenOrRedirect::Redirect);
                self.state_stack.push(TokenOrRedirect::HeadTailSeparator); // bar
                self.state_stack.push(TokenOrRedirect::Redirect);

                self.state_stack.push(TokenOrRedirect::OpenList(cell));
            },
            HeapCellValue::Addr(Addr::HeapCell(h)) =>
                self.outputter.append(format!("_{}", h).as_str()),
            HeapCellValue::Addr(Addr::StackCell(fr, sc)) =>
                self.outputter.append(format!("s_{}_{}", fr, sc).as_str()),
            HeapCellValue::Addr(Addr::Str(_)) => {}
        }
    }

    fn at_cdr(&mut self, tr: &str) -> bool {
        let len = self.outputter.len();

        if self.outputter.ends_with(" | ") {
            self.outputter.truncate(len - 3);
            self.outputter.append(tr);

            true
        } else {
            false
        }
    }

    pub fn print(mut self) -> Outputter {
        loop {
            if let Some(loc_data) = self.state_stack.pop() {
                match loc_data {
                    TokenOrRedirect::Space =>
                        self.outputter.append(" "),
                    TokenOrRedirect::Atom(atom) =>
                        self.outputter.append(atom.as_str()),
                    TokenOrRedirect::Redirect => {
                        let heap_val = self.iter.next().unwrap();
                        self.handle_heap_term(heap_val);
                    },
                    TokenOrRedirect::Close =>
                        self.outputter.append(")"),
                    TokenOrRedirect::Open =>
                        self.outputter.append("("),
                    TokenOrRedirect::OpenList(delimit) =>
                        if !self.at_cdr(", ") {
                            self.outputter.append("[");
                        } else {
                            delimit.set(false);
                        },
                    TokenOrRedirect::CloseList(delimit) =>
                        if delimit.get() == true {
                            self.outputter.append("]");
                        },
                    TokenOrRedirect::HeadTailSeparator =>
                        self.outputter.append(" | "),
                    TokenOrRedirect::Comma =>
                        self.outputter.append(", ")
                }
            } else if let Some(heap_val) = self.iter.next() {
                self.handle_heap_term(heap_val);
            } else {
                break;
            }
        }

        self.outputter
    }
}
<commit_msg>minor tweak to printer code<commit_after>use prolog::ast::*;
use prolog::heap_iter::*;

use std::cell::Cell;
use std::rc::Rc;

#[derive(Clone)]
pub enum TokenOrRedirect {
    Atom(ClauseName),
    Redirect,
    Open,
    Close,
    Comma,
    OpenList(Rc<Cell<bool>>),
    CloseList(Rc<Cell<bool>>),
    HeadTailSeparator,
    Space
}

pub trait HeapCellValueFormatter {
    // this function belongs to the display predicate formatter, which it uses
    // to format all clauses.
    fn format_struct(&self, arity: usize, name: ClauseName, state_stack: &mut Vec<TokenOrRedirect>)
    {
        state_stack.push(TokenOrRedirect::Close);

        for _ in 0 .. arity {
            state_stack.push(TokenOrRedirect::Redirect);
            state_stack.push(TokenOrRedirect::Comma);
        }

        state_stack.pop();
        state_stack.push(TokenOrRedirect::Open);

        state_stack.push(TokenOrRedirect::Atom(name));
    }

    // this can be overloaded to handle special cases, falling back on the default of
    // format_struct when convenient.
    fn format_clause(&self, usize, ClauseType, &mut Vec<TokenOrRedirect>);
}

pub trait HeapCellValueOutputter {
    type Output;

    fn new() -> Self;
    fn append(&mut self, &str);
    fn begin_new_var(&mut self);
    fn result(self) -> Self::Output;
    fn ends_with(&self, &str) -> bool;
    fn len(&self) -> usize;
    fn truncate(&mut self, usize);
}

pub struct PrinterOutputter {
    contents: String
}

impl HeapCellValueOutputter for PrinterOutputter {
    type Output = String;

    fn new() -> Self {
        PrinterOutputter { contents: String::new() }
    }

    fn append(&mut self, contents: &str) {
        self.contents += contents;
    }

    fn begin_new_var(&mut self) {
        if self.contents.len() != 0 {
            self.contents += ", ";
        }
    }

    fn result(self) -> Self::Output {
        self.contents
    }

    fn ends_with(&self, s: &str) -> bool {
        self.contents.ends_with(s)
    }

    fn len(&self) -> usize {
        self.contents.len()
    }

    fn truncate(&mut self, len: usize) {
        self.contents.truncate(len);
    }
}

// the 'classic' display corresponding to the display predicate.
pub struct DisplayFormatter {}

impl HeapCellValueFormatter for DisplayFormatter {
    fn format_clause(&self, arity: usize, ct: ClauseType, state_stack: &mut Vec<TokenOrRedirect>)
    {
        if ct.fixity().is_some() {
            let mut new_name = String::from("'");
            new_name += ct.name().as_str();
            new_name += "'";

            self.format_struct(arity, ct.name(), state_stack);
        } else {
            self.format_struct(arity, ct.name(), state_stack);
        }
    }
}

pub struct TermFormatter {}

impl HeapCellValueFormatter for TermFormatter {
    fn format_clause(&self, arity: usize, ct: ClauseType, state_stack: &mut Vec<TokenOrRedirect>)
    {
        if let Some(fixity) = ct.fixity() {
            match fixity {
                Fixity::Post => {
                    state_stack.push(TokenOrRedirect::Atom(ct.name()));
                    state_stack.push(TokenOrRedirect::Space);
                    state_stack.push(TokenOrRedirect::Redirect);
                },
                Fixity::Pre => {
                    state_stack.push(TokenOrRedirect::Redirect);
                    state_stack.push(TokenOrRedirect::Space);
                    state_stack.push(TokenOrRedirect::Atom(ct.name()));
                },
                Fixity::In => {
                    state_stack.push(TokenOrRedirect::Redirect);
                    state_stack.push(TokenOrRedirect::Space);
                    state_stack.push(TokenOrRedirect::Atom(ct.name()));
                    state_stack.push(TokenOrRedirect::Space);
                    state_stack.push(TokenOrRedirect::Redirect);
                }
            }
        } else {
            self.format_struct(arity, ct.name(), state_stack);
        }
    }
}

pub struct HeapCellPrinter<'a, Formatter, Outputter> {
    formatter:   Formatter,
    outputter:   Outputter,
    iter:        HeapCellPreOrderIterator<'a>,
    state_stack: Vec<TokenOrRedirect>
}

impl<'a, Formatter: HeapCellValueFormatter, Outputter: HeapCellValueOutputter>
    HeapCellPrinter<'a, Formatter, Outputter>
{
    pub fn new(iter: HeapCellPreOrderIterator<'a>, formatter: Formatter, outputter: Outputter)
               -> Self
    {
        HeapCellPrinter { formatter, outputter, iter, state_stack: vec![] }
    }

    fn handle_heap_term(&mut self, heap_val: HeapCellValue) {
        match heap_val {
            HeapCellValue::NamedStr(arity, name, fixity) => {
                let ct = ClauseType::from(name, arity, fixity);
                self.formatter.format_clause(arity, ct, &mut self.state_stack)
            },
            HeapCellValue::Addr(Addr::Con(Constant::EmptyList)) =>
                if !self.at_cdr("") {
                    self.outputter.append("[]");
                },
            HeapCellValue::Addr(Addr::Con(c)) =>
                self.outputter.append(format!("{}", c).as_str()),
            HeapCellValue::Addr(Addr::Lis(_)) => {
                let cell = Rc::new(Cell::new(true));

                self.state_stack.push(TokenOrRedirect::CloseList(cell.clone()));

                self.state_stack.push(TokenOrRedirect::Redirect);
                self.state_stack.push(TokenOrRedirect::HeadTailSeparator); // bar
                self.state_stack.push(TokenOrRedirect::Redirect);

                self.state_stack.push(TokenOrRedirect::OpenList(cell));
            },
            HeapCellValue::Addr(Addr::HeapCell(h)) =>
                self.outputter.append(format!("_{}", h).as_str()),
            HeapCellValue::Addr(Addr::StackCell(fr, sc)) =>
                self.outputter.append(format!("s_{}_{}", fr, sc).as_str()),
            HeapCellValue::Addr(Addr::Str(_)) => {}
        }
    }

    fn at_cdr(&mut self, tr: &str) -> bool {
        let len = self.outputter.len();

        if self.outputter.ends_with(" | ") {
            self.outputter.truncate(len - 3);
            self.outputter.append(tr);

            true
        } else {
            false
        }
    }

    pub fn print(mut self) -> Outputter {
        loop {
            if let Some(loc_data) = self.state_stack.pop() {
                match loc_data {
                    TokenOrRedirect::Space =>
                        self.outputter.append(" "),
                    TokenOrRedirect::Atom(atom) =>
                        self.outputter.append(atom.as_str()),
                    TokenOrRedirect::Redirect => {
                        let heap_val = self.iter.next().unwrap();
                        self.handle_heap_term(heap_val);
                    },
                    TokenOrRedirect::Close =>
                        self.outputter.append(")"),
                    TokenOrRedirect::Open =>
                        self.outputter.append("("),
                    TokenOrRedirect::OpenList(delimit) =>
                        if !self.at_cdr(", ") {
                            self.outputter.append("[");
                        } else {
                            delimit.set(false);
                        },
                    TokenOrRedirect::CloseList(delimit) =>
                        if delimit.get() {
                            self.outputter.append("]");
                        },
                    TokenOrRedirect::HeadTailSeparator =>
                        self.outputter.append(" | "),
                    TokenOrRedirect::Comma =>
                        self.outputter.append(", ")
                }
            } else if let Some(heap_val) = self.iter.next() {
                self.handle_heap_term(heap_val);
            } else {
                break;
            }
        }

        self.outputter
    }
}
<|endoftext|>


<commit_before>pub mod line;

use core::codepointinfo::CodepointInfo;

use self::line::Line;

#[derive(Debug, Clone)]
struct Dimension {
    l: usize,
    c: usize,
    w: usize,
    h: usize,
}

// the screen is composed of lines
#[derive(Debug, Clone)]
pub struct Screen {
    pub line: Vec<Line>,
    pub used: usize, // number of used line
    pub width: usize,
    pub height: usize,
}

impl Screen {
    pub fn new(width: usize, height: usize) -> Screen {
        let mut line: Vec<Line> = Vec::new();
        for _ in 0..height {
            line.push(Line::new(width));
        }

        Screen {
            line: line,
            used: 0,
            width: width,
            height: height,
        }
    }

    pub fn resize(&mut self, width: usize, height: usize) {

        self.line.resize(height, Line::new(width));
        for i in 0..height {
            self.line[i].chars.resize(width, CodepointInfo::new());
            self.line[i].width = width;
            self.line[i].used = 0;
        }
        self.width = width;
        self.height = height;
        self.used = 0;
    }

    /// append
    pub fn push(&mut self, cpi: CodepointInfo) -> (bool, usize) {
        if self.used == self.height {
            return (false, self.used);
        }
        if self.line[self.used].used >= self.line[self.used].width {
            self.used += 1;
        }
        if self.used >= self.height {
            return (false, self.used);
        }

        let cp = cpi.cp;
        let line = &mut self.line[self.used];
        let (ok, _) = line.push(cpi);

        if ok == true {
            if cp == '\n' || cp == '\r' {
                self.used += 1;
            }
        }
        (ok, self.used)
    }

    pub fn clear(&mut self) {
        for h in 0..self.height {
            self.line[h].clear();
        }
        self.used = 0;
    }

    pub fn get_mut_line(&mut self, index: usize) -> Option<&mut Line> {
        if index < self.height {
            Some(&mut self.line[index])
        } else {
            None
        }
    }

    pub fn get_line(&self, index: usize) -> Option<&Line> {
        if index < self.height {
            Some(&self.line[index])
        } else {
            None
        }
    }

    pub fn get_mut_used_line(&mut self, index: usize) -> Option<&mut Line> {
        if index < self.used {
            Some(&mut self.line[index])
        } else {
            None
        }
    }

    pub fn get_used_line(&self, index: usize) -> Option<&Line> {
        if index < self.used {
            Some(&self.line[index])
        } else {
            None
        }
    }

    pub fn get_cpinfo(&self, x: usize, y: usize) -> Option<&CodepointInfo> {
        match self.get_line(y) {
            None => None,
            Some(l) => l.get_cpi(x),
        }
    }

    pub fn get_mut_cpinfo(&mut self, x: usize, y: usize) -> Option<&mut CodepointInfo> {
        match self.get_mut_line(y) {
            None => None,
            Some(l) => l.get_mut_cpi(x),
        }
    }

    pub fn get_used_cpinfo(&self, x: usize, y: usize) -> Option<&CodepointInfo> {
        match self.get_used_line(y) {
            None => None,
            Some(l) => l.get_used_cpi(x),
        }
    }

    pub fn get_mut_used_cpinfo(&mut self, x: usize, y: usize) -> Option<&mut CodepointInfo> {
        match self.get_mut_used_line(y) {
            None => None,
            Some(l) => l.get_mut_used_cpi(x),
        }
    }
}

#[test]
fn test_screen() {

    let mut scr = Screen::new(640, 480);
    assert_eq!(640, scr.width);
    assert_eq!(480, scr.height);
    assert_eq!(scr.height, scr.line.len());
    assert_eq!(scr.width, scr.line[0].chars.len());

    scr.resize(800, 600);
    assert_eq!(800, scr.width);
    assert_eq!(600, scr.height);
    assert_eq!(scr.height, scr.line.len());
    assert_eq!(scr.width, scr.line[0].chars.len());

    scr.resize(1024, 768);
    assert_eq!(1024, scr.width);
    assert_eq!(768, scr.height);
    assert_eq!(scr.height, scr.line.len());
    assert_eq!(scr.width, scr.line[0].chars.len());

    scr.resize(640, 480);
    assert_eq!(640, scr.width);
    assert_eq!(480, scr.height);
    assert_eq!(scr.height, scr.line.len());
    assert_eq!(scr.width, scr.line[0].chars.len());
}
<commit_msg>Screen : add functions get_mut_first_cpinfo, get_mut_last_cpinfo, get_first_cpinfo, get_last_cpinfo<commit_after>pub mod line;

use core::codepointinfo::CodepointInfo;

use self::line::Line;

#[derive(Debug, Clone)]
struct Dimension {
    l: usize,
    c: usize,
    w: usize,
    h: usize,
}

// the screen is composed of lines
#[derive(Debug, Clone)]
pub struct Screen {
    pub line: Vec<Line>,
    pub used: usize, // number of used line
    pub width: usize,
    pub height: usize,
}

impl Screen {
    pub fn new(width: usize, height: usize) -> Screen {
        let mut line: Vec<Line> = Vec::new();
        for _ in 0..height {
            line.push(Line::new(width));
        }

        Screen {
            line: line,
            used: 0,
            width: width,
            height: height,
        }
    }

    pub fn resize(&mut self, width: usize, height: usize) {

        self.line.resize(height, Line::new(width));
        for i in 0..height {
            self.line[i].chars.resize(width, CodepointInfo::new());
            self.line[i].width = width;
            self.line[i].used = 0;
        }
        self.width = width;
        self.height = height;
        self.used = 0;
    }

    /// append
    pub fn push(&mut self, cpi: CodepointInfo) -> (bool, usize) {
        if self.used == self.height {
            return (false, self.used);
        }
        if self.line[self.used].used >= self.line[self.used].width {
            self.used += 1;
        }
        if self.used >= self.height {
            return (false, self.used);
        }

        let cp = cpi.cp;
        let line = &mut self.line[self.used];
        let (ok, _) = line.push(cpi);

        if ok == true {
            if cp == '\n' || cp == '\r' {
                self.used += 1;
            }
        }
        (ok, self.used)
    }

    pub fn clear(&mut self) {
        for h in 0..self.height {
            self.line[h].clear();
        }
        self.used = 0;
    }

    pub fn get_mut_line(&mut self, index: usize) -> Option<&mut Line> {
        if index < self.height {
            Some(&mut self.line[index])
        } else {
            None
        }
    }

    pub fn get_line(&self, index: usize) -> Option<&Line> {
        if index < self.height {
            Some(&self.line[index])
        } else {
            None
        }
    }

    pub fn get_mut_used_line(&mut self, index: usize) -> Option<&mut Line> {
        if index < self.used {
            Some(&mut self.line[index])
        } else {
            None
        }
    }

    pub fn get_used_line(&self, index: usize) -> Option<&Line> {
        if index < self.used {
            Some(&self.line[index])
        } else {
            None
        }
    }

    pub fn get_cpinfo(&self, x: usize, y: usize) -> Option<&CodepointInfo> {
        match self.get_line(y) {
            None => None,
            Some(l) => l.get_cpi(x),
        }
    }

    pub fn get_mut_cpinfo(&mut self, x: usize, y: usize) -> Option<&mut CodepointInfo> {
        match self.get_mut_line(y) {
            None => None,
            Some(l) => l.get_mut_cpi(x),
        }
    }

    pub fn get_used_cpinfo(&self, x: usize, y: usize) -> Option<&CodepointInfo> {
        match self.get_used_line(y) {
            None => None,
            Some(l) => l.get_used_cpi(x),
        }
    }

    pub fn get_mut_used_cpinfo(&mut self, x: usize, y: usize) -> Option<&mut CodepointInfo> {
        match self.get_mut_used_line(y) {
            None => None,
            Some(l) => l.get_mut_used_cpi(x),
        }
    }

    pub fn get_mut_first_cpinfo(&mut self) -> (Option<&mut CodepointInfo>, usize, usize) {
        match self.get_mut_used_line(0) {
            None => (None, 0, 0),
            Some(l) => (l.get_mut_used_cpi(0), 0, 0),
        }
    }

    pub fn get_mut_last_cpinfo(&mut self) -> (Option<&mut CodepointInfo>, usize, usize) {
        let y = self.used;
        match self.get_mut_used_line(y) {
            None => (None, 0, 0),
            Some(l) => {
                let x = l.used;
                (l.get_mut_used_cpi(0), x, y)
            }
        }
    }

    pub fn get_first_cpinfo(&self) -> (Option<&CodepointInfo>, usize, usize) {
        match self.get_used_line(0) {
            None => (None, 0, 0),
            Some(l) => (l.get_used_cpi(0), 0, 0),
        }
    }

    pub fn get_last_cpinfo(&self) -> (Option<&CodepointInfo>, usize, usize) {
        let y = self.used;
        match self.get_used_line(y) {
            None => (None, 0, 0),
            Some(l) => {
                let x = l.used;
                (l.get_used_cpi(0), x, y)
            }
        }
    }
}

#[test]
fn test_screen() {

    let mut scr = Screen::new(640, 480);
    assert_eq!(640, scr.width);
    assert_eq!(480, scr.height);
    assert_eq!(scr.height, scr.line.len());
    assert_eq!(scr.width, scr.line[0].chars.len());

    scr.resize(800, 600);
    assert_eq!(800, scr.width);
    assert_eq!(600, scr.height);
    assert_eq!(scr.height, scr.line.len());
    assert_eq!(scr.width, scr.line[0].chars.len());

    scr.resize(1024, 768);
    assert_eq!(1024, scr.width);
    assert_eq!(768, scr.height);
    assert_eq!(scr.height, scr.line.len());
    assert_eq!(scr.width, scr.line[0].chars.len());

    scr.resize(640, 480);
    assert_eq!(640, scr.width);
    assert_eq!(480, scr.height);
    assert_eq!(scr.height, scr.line.len());
    assert_eq!(scr.width, scr.line[0].chars.len());
}
<|endoftext|>


<commit_before>use std::fmt::{Debug, Error, Formatter};
use std::path::{Path, PathBuf};
use std::process::{Command, Output};
use std::{env, str};

pub struct TestCommand {
    cwd: PathBuf,
    args: Vec<String>,
    env_vars: Vec<(String, String)>,
}

impl TestCommand {
    pub fn new(cwd: &Path, subcommand: &str) -> Self {
        TestCommand {
            cwd: cwd.into(),
            args: vec![subcommand.into()],
            env_vars: Vec::new(),
        }
    }

    pub fn arg<S: Into<String>>(mut self, value: S) -> Self {
        self.args.push(value.into());
        self
    }

    pub fn args<I>(self, values: I) -> Self
    where
        I: IntoIterator,
        I::Item: Into<String>,
    {
        values.into_iter().fold(self, |c, value| c.arg(value))
    }

    pub fn env(mut self, key: &str, value: &str) -> Self {
        self.env_vars.push((key.into(), value.into()));
        self
    }

    pub fn run(self) -> CommandResult {
        let output = self.build_command().output().unwrap();
        CommandResult { output: output }
    }

    fn build_command(&self) -> Command {
        let mut command = Command::new(path_to_diesel_cli());
        command.args(&self.args).current_dir(&self.cwd);
        for &(ref k, ref v) in self.env_vars.iter() {
            command.env(&k, &v);
        }
        command
    }
}

pub struct CommandResult {
    output: Output,
}

impl CommandResult {
    pub fn is_success(&self) -> bool {
        self.output.status.success()
    }

    pub fn stdout(&self) -> &str {
        str::from_utf8(&self.output.stdout).unwrap()
    }

    pub fn stderr(&self) -> &str {
        str::from_utf8(&self.output.stderr).unwrap()
    }

    pub fn code(&self) -> i32 {
        self.output.status.code().unwrap()
    }

    #[allow(dead_code)]
    pub fn result(self) -> Result<Self, Self> {
        if self.is_success() {
            Ok(self)
        } else {
            Err(self)
        }
    }
}

fn path_to_diesel_cli() -> PathBuf {
    Path::new(&env::var_os("CARGO_MANIFEST_DIR").unwrap())
        .parent()
        .unwrap()
        .join("target")
        .join("debug")
        .join("diesel")
}

impl Debug for CommandResult {
    fn fmt(&self, out: &mut Formatter) -> Result<(), Error> {
        write!(out, "stdout: {}\nstderr: {}", self.stdout(), self.stderr())
    }
}
<commit_msg>Allow setting a specific test bin<commit_after>use std::fmt::{Debug, Error, Formatter};
use std::path::{Path, PathBuf};
use std::process::{Command, Output};
use std::{env, str};

pub struct TestCommand {
    cwd: PathBuf,
    args: Vec<String>,
    env_vars: Vec<(String, String)>,
}

impl TestCommand {
    pub fn new(cwd: &Path, subcommand: &str) -> Self {
        TestCommand {
            cwd: cwd.into(),
            args: vec![subcommand.into()],
            env_vars: Vec::new(),
        }
    }

    pub fn arg<S: Into<String>>(mut self, value: S) -> Self {
        self.args.push(value.into());
        self
    }

    pub fn args<I>(self, values: I) -> Self
    where
        I: IntoIterator,
        I::Item: Into<String>,
    {
        values.into_iter().fold(self, |c, value| c.arg(value))
    }

    pub fn env(mut self, key: &str, value: &str) -> Self {
        self.env_vars.push((key.into(), value.into()));
        self
    }

    pub fn run(self) -> CommandResult {
        let output = self
            .build_command()
            .output()
            .expect("failed to execute process");
        CommandResult { output: output }
    }

    fn build_command(&self) -> Command {
        let mut command = Command::new(path_to_diesel_cli());
        command.args(&self.args).current_dir(&self.cwd);
        for &(ref k, ref v) in self.env_vars.iter() {
            command.env(&k, &v);
        }
        command
    }
}

pub struct CommandResult {
    output: Output,
}

impl CommandResult {
    pub fn is_success(&self) -> bool {
        self.output.status.success()
    }

    pub fn stdout(&self) -> &str {
        str::from_utf8(&self.output.stdout).unwrap()
    }

    pub fn stderr(&self) -> &str {
        str::from_utf8(&self.output.stderr).unwrap()
    }

    pub fn code(&self) -> i32 {
        self.output.status.code().unwrap()
    }

    #[allow(dead_code)]
    pub fn result(self) -> Result<Self, Self> {
        if self.is_success() {
            Ok(self)
        } else {
            Err(self)
        }
    }
}

fn path_to_diesel_cli() -> PathBuf {
    if let Some(path) = env::var_os("DIESEL_TEST_BIN") {
        Path::new(&path).into()
    } else {
        Path::new(&env::var_os("CARGO_MANIFEST_DIR").unwrap())
            .parent()
            .unwrap()
            .join("target")
            .join("debug")
            .join("diesel")
    }
}

impl Debug for CommandResult {
    fn fmt(&self, out: &mut Formatter) -> Result<(), Error> {
        write!(out, "stdout: {}\nstderr: {}", self.stdout(), self.stderr())
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]
#![allow(unused_must_use)]

use std::collections::HashMap;

use mio::{Token, Handler, EventLoop, EventSet, PollOpt};
use mio::tcp::{TcpListener, TcpStream};

use raftserver::{SERVER_TOKEN, FIRST_CUSTOM_TOKEN, DEFAULT_BASE_TICK_MS, INVALID_TOKEN};
use raftserver::{Msg, Sender, Result, ConnData, TimerMsg};
use raftserver::conn::Conn;
use raftserver::handler::ServerHandler;

pub struct Server<T: ServerHandler> {
    pub listener: TcpListener,
    pub conns: HashMap<Token, Conn>,
    pub token_counter: usize,
    pub sender: Sender,

    peers: HashMap<String, Token>,
    handler: T,
}

impl<T: ServerHandler> Server<T> {
    pub fn new(h: T, l: TcpListener, sender: Sender) -> Server<T> {
        Server {
            handler: h,
            listener: l,
            sender: sender,
            conns: HashMap::new(),
            peers: HashMap::new(),
            token_counter: FIRST_CUSTOM_TOKEN.as_usize(),
        }
    }

    pub fn register_tick(&mut self, event_loop: &mut EventLoop<Server<T>>) -> Result<()> {
        let token = Msg::Tick;
        // must ok, maybe check error later.
        event_loop.timeout_ms(token, DEFAULT_BASE_TICK_MS);
        Ok(())
    }

    fn register_timer(&mut self,
                      event_loop: &mut EventLoop<Server<T>>,
                      delay: u64,
                      msg: TimerMsg) {
        let token = Msg::Timer {
            delay: delay,
            msg: msg,
        };
        event_loop.timeout_ms(token, delay);
    }

    fn remove_conn(&mut self, event_loop: &mut EventLoop<Server<T>>, token: Token) {
        let conn = self.conns.remove(&token);
        match conn {
            Some(conn) => {
                // if connected to remote peer, remove this too.
                if let Some(addr) = conn.peer_addr {
                    self.peers.remove(&addr);
                }

                event_loop.deregister(&conn.sock);
            }
            None => {
                warn!("missing connection for token {}", token.as_usize());
            }
        }
    }

    fn add_new_conn(&mut self,
                    event_loop: &mut EventLoop<Server<T>>,
                    sock: TcpStream,
                    peer_addr: Option<String>)
                    -> Result<(Token)> {
        let new_token = Token(self.token_counter);
        self.token_counter += 1;

        try!(sock.set_nodelay(true));

        let conn = Conn::new(sock, new_token, peer_addr);

        self.conns.insert(new_token, conn);

        try!(event_loop.register(&self.conns[&new_token].sock,
                                 new_token,
                                 EventSet::readable() | EventSet::hup(),
                                 PollOpt::edge())
                       .or_else(|e| {
                           // register error, remove from conn map.
                           self.conns.remove(&new_token);
                           Err(e)
                       }));
        Ok(new_token)
    }

    fn handle_readeable(&mut self, event_loop: &mut EventLoop<Server<T>>, token: Token) {
        match token {
            SERVER_TOKEN => {
                loop {
                    // For edge trigger, we must accept all connections until None.
                    let sock = match self.listener.accept() {
                        Err(e) => {
                            error!("accept error: {:?}", e);
                            return;
                        }
                        Ok(None) => {
                            debug!("no connection, accept later.");
                            return;
                        }
                        Ok(Some((sock, addr))) => {
                            debug!("accept conn {}", addr);
                            sock
                        }
                    };

                    self.add_new_conn(event_loop, sock, None)
                        .map_err(|e| {
                            error!("register conn err {:?}", e);
                        });
                }
            }
            token => {
                let msgs = match self.conns.get_mut(&token) {
                    None => {
                        warn!("missing conn for token {:?}", token);
                        return;
                    }
                    Some(conn) => conn.read(event_loop),
                };

                msgs.and_then(|msgs| {
                        if msgs.len() == 0 {
                            return Ok(msgs);
                        }

                        self.handler.handle_read_data(&self.sender, token, msgs)
                    })
                    .and_then(|res| {
                        if res.len() == 0 {
                            return Ok(());
                        }

                        // append to write buffer here, no need using sender to notify.
                        if let Some(conn) = self.conns.get_mut(&token) {
                            for data in res {
                                try!(conn.append_write_buf(event_loop, data));
                            }
                        }
                        Ok(())
                    })
                    .map_err(|e| {
                        warn!("handle read conn err {:?}, remove", e);
                        self.remove_conn(event_loop, token);
                    });
            }

        }
    }

    fn handle_writable(&mut self, event_loop: &mut EventLoop<Server<T>>, token: Token) {
        let res = match self.conns.get_mut(&token) {
            None => {
                warn!("missing conn for token {:?}", token);
                return;
            }
            Some(conn) => conn.write(event_loop),
        };

        res.map_err(|e| {
            warn!("handle write conn err {:?}, remove", e);
            self.remove_conn(event_loop, token);
        });
    }

    fn handle_writedata(&mut self,
                        event_loop: &mut EventLoop<Server<T>>,
                        token: Token,
                        data: ConnData) {
        let res = match self.conns.get_mut(&token) {
            None => {
                warn!("missing conn for token {:?}", token);
                return;
            }
            Some(conn) => conn.append_write_buf(event_loop, data),
        };

        res.map_err(|e| {
            warn!("handle write data err {:?}, remove", e);
            self.remove_conn(event_loop, token);
        });
    }

    fn handle_tick(&mut self, event_loop: &mut EventLoop<Server<T>>) {
        self.handler
            .handle_tick(&self.sender)
            .map_err(|e| warn!("handle tick err {:?}", e));

        self.register_tick(event_loop);
    }

    fn handle_timer(&mut self, _: &mut EventLoop<Server<T>>, msg: TimerMsg) {
        self.handler
            .handle_timer(&self.sender, msg)
            .map_err(|e| warn!("handle timer err {:?}", e));
    }

    fn connect_peer(&mut self, event_loop: &mut EventLoop<Server<T>>, addr: &str) -> Result<Token> {
        let peer_addr = try!(addr.parse());
        let sock = try!(TcpStream::connect(&peer_addr));
        let token = try!(self.add_new_conn(event_loop, sock, Some(addr.to_string())));
        self.peers.insert(addr.to_string(), token);
        Ok(token)
    }

    fn handle_sendpeer(&mut self,
                       event_loop: &mut EventLoop<Server<T>>,
                       addr: String,
                       data: ConnData) {
        // check the corresponding token for peer address.
        let mut token = self.peers.get(&addr).map_or(INVALID_TOKEN, |t| *t);

        if token == INVALID_TOKEN {
            match self.connect_peer(event_loop, &addr) {
                Err(e) => {
                    error!("connect {:?} err {:?}", addr, e);
                    return;
                }
                Ok(new_token) => token = new_token,
            }
        }

        self.handle_writedata(event_loop, token, data);
    }
}

impl<T: ServerHandler> Handler for Server<T> {
    type Timeout = Msg;
    type Message = Msg;

    fn ready(&mut self, event_loop: &mut EventLoop<Server<T>>, token: Token, events: EventSet) {
        if events.is_hup() || events.is_error() {
            self.remove_conn(event_loop, token);
            return;
        }

        if events.is_readable() {
            self.handle_readeable(event_loop, token);
        }

        if events.is_writable() {
            self.handle_writable(event_loop, token);
        }
    }

    fn notify(&mut self, event_loop: &mut EventLoop<Server<T>>, msg: Msg) {
        match msg {
            Msg::Quit => event_loop.shutdown(),
            Msg::WriteData{token, data} => self.handle_writedata(event_loop, token, data),
            Msg::Timer{delay, msg} => self.register_timer(event_loop, delay, msg),
            Msg::SendPeer{addr, data} => self.handle_sendpeer(event_loop, addr, data),
            _ => panic!("unexpected msg"),
        }
    }

    fn timeout(&mut self, event_loop: &mut EventLoop<Server<T>>, msg: Msg) {
        match msg {
            Msg::Tick => self.handle_tick(event_loop),
            Msg::Timer{msg, ..} => self.handle_timer(event_loop, msg),
            _ => panic!("unexpected msg"),
        }
    }
}
<commit_msg>raftserver: Address comment.<commit_after>#![allow(dead_code)]
#![allow(unused_must_use)]

use std::collections::HashMap;

use mio::{Token, Handler, EventLoop, EventSet, PollOpt};
use mio::tcp::{TcpListener, TcpStream};

use raftserver::{SERVER_TOKEN, FIRST_CUSTOM_TOKEN, DEFAULT_BASE_TICK_MS, INVALID_TOKEN};
use raftserver::{Msg, Sender, Result, ConnData, TimerMsg};
use raftserver::conn::Conn;
use raftserver::handler::ServerHandler;

pub struct Server<T: ServerHandler> {
    pub listener: TcpListener,
    pub conns: HashMap<Token, Conn>,
    pub token_counter: usize,
    pub sender: Sender,

    peers: HashMap<String, Token>,
    handler: T,
}

impl<T: ServerHandler> Server<T> {
    pub fn new(h: T, l: TcpListener, sender: Sender) -> Server<T> {
        Server {
            handler: h,
            listener: l,
            sender: sender,
            conns: HashMap::new(),
            peers: HashMap::new(),
            token_counter: FIRST_CUSTOM_TOKEN.as_usize(),
        }
    }

    pub fn register_tick(&mut self, event_loop: &mut EventLoop<Server<T>>) -> Result<()> {
        let token = Msg::Tick;
        // must ok, maybe check error later.
        event_loop.timeout_ms(token, DEFAULT_BASE_TICK_MS);
        Ok(())
    }

    fn register_timer(&mut self,
                      event_loop: &mut EventLoop<Server<T>>,
                      delay: u64,
                      msg: TimerMsg) {
        let token = Msg::Timer {
            delay: delay,
            msg: msg,
        };
        event_loop.timeout_ms(token, delay);
    }

    fn remove_conn(&mut self, event_loop: &mut EventLoop<Server<T>>, token: Token) {
        let conn = self.conns.remove(&token);
        match conn {
            Some(conn) => {
                // if connected to remote peer, remove this too.
                if let Some(addr) = conn.peer_addr {
                    self.peers.remove(&addr);
                }

                event_loop.deregister(&conn.sock);
            }
            None => {
                warn!("missing connection for token {}", token.as_usize());
            }
        }
    }

    fn add_new_conn(&mut self,
                    event_loop: &mut EventLoop<Server<T>>,
                    sock: TcpStream,
                    peer_addr: Option<String>)
                    -> Result<(Token)> {
        let new_token = Token(self.token_counter);
        self.token_counter += 1;

        try!(sock.set_nodelay(true));

        try!(event_loop.register(&sock,
                                 new_token,
                                 EventSet::readable() | EventSet::hup(),
                                 PollOpt::edge()));

        let conn = Conn::new(sock, new_token, peer_addr);

        self.conns.insert(new_token, conn);

        Ok(new_token)
    }

    fn handle_readeable(&mut self, event_loop: &mut EventLoop<Server<T>>, token: Token) {
        match token {
            SERVER_TOKEN => {
                loop {
                    // For edge trigger, we must accept all connections until None.
                    let sock = match self.listener.accept() {
                        Err(e) => {
                            error!("accept error: {:?}", e);
                            return;
                        }
                        Ok(None) => {
                            debug!("no connection, accept later.");
                            return;
                        }
                        Ok(Some((sock, addr))) => {
                            debug!("accept conn {}", addr);
                            sock
                        }
                    };

                    self.add_new_conn(event_loop, sock, None)
                        .map_err(|e| {
                            error!("register conn err {:?}", e);
                        });
                }
            }
            token => {
                let msgs = match self.conns.get_mut(&token) {
                    None => {
                        warn!("missing conn for token {:?}", token);
                        return;
                    }
                    Some(conn) => conn.read(event_loop),
                };

                msgs.and_then(|msgs| {
                        if msgs.len() == 0 {
                            return Ok(msgs);
                        }

                        self.handler.handle_read_data(&self.sender, token, msgs)
                    })
                    .and_then(|res| {
                        if res.len() == 0 {
                            return Ok(());
                        }

                        // append to write buffer here, no need using sender to notify.
                        if let Some(conn) = self.conns.get_mut(&token) {
                            for data in res {
                                try!(conn.append_write_buf(event_loop, data));
                            }
                        }
                        Ok(())
                    })
                    .map_err(|e| {
                        warn!("handle read conn err {:?}, remove", e);
                        self.remove_conn(event_loop, token);
                    });
            }

        }
    }

    fn handle_writable(&mut self, event_loop: &mut EventLoop<Server<T>>, token: Token) {
        let res = match self.conns.get_mut(&token) {
            None => {
                warn!("missing conn for token {:?}", token);
                return;
            }
            Some(conn) => conn.write(event_loop),
        };

        res.map_err(|e| {
            warn!("handle write conn err {:?}, remove", e);
            self.remove_conn(event_loop, token);
        });
    }

    fn handle_writedata(&mut self,
                        event_loop: &mut EventLoop<Server<T>>,
                        token: Token,
                        data: ConnData) {
        let res = match self.conns.get_mut(&token) {
            None => {
                warn!("missing conn for token {:?}", token);
                return;
            }
            Some(conn) => conn.append_write_buf(event_loop, data),
        };

        res.map_err(|e| {
            warn!("handle write data err {:?}, remove", e);
            self.remove_conn(event_loop, token);
        });
    }

    fn handle_tick(&mut self, event_loop: &mut EventLoop<Server<T>>) {
        self.handler
            .handle_tick(&self.sender)
            .map_err(|e| warn!("handle tick err {:?}", e));

        self.register_tick(event_loop);
    }

    fn handle_timer(&mut self, _: &mut EventLoop<Server<T>>, msg: TimerMsg) {
        self.handler
            .handle_timer(&self.sender, msg)
            .map_err(|e| warn!("handle timer err {:?}", e));
    }

    fn connect_peer(&mut self, event_loop: &mut EventLoop<Server<T>>, addr: &str) -> Result<Token> {
        let peer_addr = try!(addr.parse());
        let sock = try!(TcpStream::connect(&peer_addr));
        let token = try!(self.add_new_conn(event_loop, sock, Some(addr.to_string())));
        self.peers.insert(addr.to_string(), token);
        Ok(token)
    }

    fn handle_sendpeer(&mut self,
                       event_loop: &mut EventLoop<Server<T>>,
                       addr: String,
                       data: ConnData) {
        // check the corresponding token for peer address.
        let mut token = self.peers.get(&addr).map_or(INVALID_TOKEN, |t| *t);

        if token == INVALID_TOKEN {
            match self.connect_peer(event_loop, &addr) {
                Err(e) => {
                    error!("connect {:?} err {:?}", addr, e);
                    return;
                }
                Ok(new_token) => token = new_token,
            }
        }

        self.handle_writedata(event_loop, token, data);
    }
}

impl<T: ServerHandler> Handler for Server<T> {
    type Timeout = Msg;
    type Message = Msg;

    fn ready(&mut self, event_loop: &mut EventLoop<Server<T>>, token: Token, events: EventSet) {
        if events.is_hup() || events.is_error() {
            self.remove_conn(event_loop, token);
            return;
        }

        if events.is_readable() {
            self.handle_readeable(event_loop, token);
        }

        if events.is_writable() {
            self.handle_writable(event_loop, token);
        }
    }

    fn notify(&mut self, event_loop: &mut EventLoop<Server<T>>, msg: Msg) {
        match msg {
            Msg::Quit => event_loop.shutdown(),
            Msg::WriteData{token, data} => self.handle_writedata(event_loop, token, data),
            Msg::Timer{delay, msg} => self.register_timer(event_loop, delay, msg),
            Msg::SendPeer{addr, data} => self.handle_sendpeer(event_loop, addr, data),
            _ => panic!("unexpected msg"),
        }
    }

    fn timeout(&mut self, event_loop: &mut EventLoop<Server<T>>, msg: Msg) {
        match msg {
            Msg::Tick => self.handle_tick(event_loop),
            Msg::Timer{msg, ..} => self.handle_timer(event_loop, msg),
            _ => panic!("unexpected msg"),
        }
    }
}
<|endoftext|>


<commit_before>use rand::Rng;

pub struct ReservoirSampling<T, R>
where
    R: Rng,
{
    k: usize,
    rng: R,
    reservoir: Vec<T>,
    i: usize,
    skip_until: usize,
}

impl<T, R> ReservoirSampling<T, R>
where
    R: Rng,
{
    pub fn new(k: usize, rng: R) -> ReservoirSampling<T, R> {
        ReservoirSampling {
            k: k,
            rng: rng,
            reservoir: vec![],
            i: 0,
            skip_until: 0,
        }
    }

    pub fn k(&self) -> usize {
        self.k
    }

    pub fn reservoir(&self) -> &Vec<T> {
        &self.reservoir
    }

    pub fn i(&self) -> usize {
        self.i
    }

    pub fn add(&mut self, obj: T) {
        let t = self.k * 4; // TODO: make this a parameter

        if self.i < self.k {
            // initial fill-up
            self.reservoir.push(obj)
        } else if self.i < t {
            // normal reservoir sampling
            let j = self.rng.gen_range::<usize>(0, self.i);
            if j < self.k {
                self.reservoir[j] = obj;
            }
        } else if self.i >= self.skip_until {
            // fast skipping approximation
            let j = self.rng.gen_range::<usize>(0, self.k);
            self.reservoir[j] = obj;

            // calculate next skip
            let p = (self.k as f64) / ((self.i + 1) as f64);
            let u = 1. - self.rng.gen_range::<f64>(0., 1.); // (0.0, 1.0]
            let g = (u.ln() / (1. - p).ln()).floor() as usize;
            self.skip_until = self.i + g;
        }

        self.i += 1;
    }

    pub fn is_empty(&self) -> bool {
        self.i == 0
    }
}

#[cfg(test)]
mod tests {
    use super::ReservoirSampling;
    use rand;

    #[test]
    fn getter() {
        let rs = ReservoirSampling::<u64, rand::ThreadRng>::new(10, rand::thread_rng());
        assert_eq!(rs.k(), 10);
        assert_eq!(rs.i(), 0);
        assert_eq!(rs.reservoir(), &vec![]);
    }

    #[test]
    fn empty() {
        let rs = ReservoirSampling::<u64, rand::ThreadRng>::new(10, rand::thread_rng());
        assert!(rs.is_empty());
        assert!(rs.reservoir().is_empty());
    }

    #[test]
    fn add_k() {
        let mut rs = ReservoirSampling::<u64, rand::ThreadRng>::new(10, rand::thread_rng());
        for i in 0..10 {
            rs.add(i);
        }
        assert_eq!(rs.i(), 10);
        assert_eq!(rs.reservoir(), &vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
    }

    #[test]
    fn add_parts() {
        let mut rs = ReservoirSampling::<u64, rand::ThreadRng>::new(100, rand::thread_rng());
        for _ in 0..150 {
            rs.add(0);
        }
        for _ in 0..750 {
            rs.add(1);
        }
        for _ in 0..100 {
            rs.add(0);
        }
        assert!((rs.reservoir().iter().sum::<u64>() as i64 - 75).abs() < 5);
    }
}
<commit_msg>reservoirsampling: dbg impl<commit_after>use rand::Rng;
use std::fmt;

pub struct ReservoirSampling<T, R>
where
    R: Rng,
{
    k: usize,
    rng: R,
    reservoir: Vec<T>,
    i: usize,
    skip_until: usize,
}

impl<T, R> ReservoirSampling<T, R>
where
    R: Rng,
{
    pub fn new(k: usize, rng: R) -> ReservoirSampling<T, R> {
        ReservoirSampling {
            k: k,
            rng: rng,
            reservoir: vec![],
            i: 0,
            skip_until: 0,
        }
    }

    pub fn k(&self) -> usize {
        self.k
    }

    pub fn reservoir(&self) -> &Vec<T> {
        &self.reservoir
    }

    pub fn i(&self) -> usize {
        self.i
    }

    pub fn add(&mut self, obj: T) {
        let t = self.k * 4; // TODO: make this a parameter

        if self.i < self.k {
            // initial fill-up
            self.reservoir.push(obj)
        } else if self.i < t {
            // normal reservoir sampling
            let j = self.rng.gen_range::<usize>(0, self.i);
            if j < self.k {
                self.reservoir[j] = obj;
            }
        } else if self.i >= self.skip_until {
            // fast skipping approximation
            let j = self.rng.gen_range::<usize>(0, self.k);
            self.reservoir[j] = obj;

            // calculate next skip
            let p = (self.k as f64) / ((self.i + 1) as f64);
            let u = 1. - self.rng.gen_range::<f64>(0., 1.); // (0.0, 1.0]
            let g = (u.ln() / (1. - p).ln()).floor() as usize;
            self.skip_until = self.i + g;
        }

        self.i += 1;
    }

    pub fn is_empty(&self) -> bool {
        self.i == 0
    }
}

impl<T, R> fmt::Debug for ReservoirSampling<T, R>
where
    R: Rng,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "ReservoirSampling {{ k: {} }}", self.k)
    }
}

#[cfg(test)]
mod tests {
    use super::ReservoirSampling;
    use rand;

    #[test]
    fn getter() {
        let rs = ReservoirSampling::<u64, rand::ThreadRng>::new(10, rand::thread_rng());
        assert_eq!(rs.k(), 10);
        assert_eq!(rs.i(), 0);
        assert_eq!(rs.reservoir(), &vec![]);
    }

    #[test]
    fn empty() {
        let rs = ReservoirSampling::<u64, rand::ThreadRng>::new(10, rand::thread_rng());
        assert!(rs.is_empty());
        assert!(rs.reservoir().is_empty());
    }

    #[test]
    fn add_k() {
        let mut rs = ReservoirSampling::<u64, rand::ThreadRng>::new(10, rand::thread_rng());
        for i in 0..10 {
            rs.add(i);
        }
        assert_eq!(rs.i(), 10);
        assert_eq!(rs.reservoir(), &vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
    }

    #[test]
    fn add_parts() {
        let mut rs = ReservoirSampling::<u64, rand::ThreadRng>::new(100, rand::thread_rng());
        for _ in 0..150 {
            rs.add(0);
        }
        for _ in 0..750 {
            rs.add(1);
        }
        for _ in 0..100 {
            rs.add(0);
        }
        assert!((rs.reservoir().iter().sum::<u64>() as i64 - 75).abs() < 5);
    }

    #[test]
    fn debug() {
        let rs = ReservoirSampling::<u64, rand::ThreadRng>::new(10, rand::thread_rng());
        assert_eq!(format!("{:?}", rs), "ReservoirSampling { k: 10 }");
    }
}
<|endoftext|>