<commit_before>use std::collections::HashMap;
use amqp_error::{AMQPError, AMQPResult};
use std::io::{Read, Write};
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};

#[derive(Debug, Clone)]
pub enum TableEntry {
    Bool(bool),
    ShortShortInt(i8),
    ShortShortUint(u8),
    ShortInt(i16),
    ShortUint(u16),
    LongInt(i32),
    LongUint(u32),
    LongLongInt(i64),
    LongLongUint(u64),
    Float(f32),
    Double(f64),
    DecimalValue(u8, u32),
    // ShortString(String),
    LongString(String),
    FieldArray(Vec<TableEntry>),
    Timestamp(u64),
    FieldTable(Table),
    Void,
}

pub type Table = HashMap<String, TableEntry>;

pub trait Init {
    fn new() -> Self;
}

impl Init for Table {
    fn new() -> Self {
        HashMap::new()
    }
}

fn read_table_entry(reader: &mut &[u8]) -> AMQPResult<TableEntry> {
    let entry = match try!(reader.read_u8()) {
        b't' => TableEntry::Bool(!try!(reader.read_u8()) == 0),
        b'b' => TableEntry::ShortShortInt(try!(reader.read_i8())),
        b'B' => TableEntry::ShortShortUint(try!(reader.read_u8())),
        b'U' => TableEntry::ShortInt(try!(reader.read_i16::<BigEndian>())),
        b'u' => TableEntry::ShortUint(try!(reader.read_u16::<BigEndian>())),
        b'I' => TableEntry::LongInt(try!(reader.read_i32::<BigEndian>())),
        b'i' => TableEntry::LongUint(try!(reader.read_u32::<BigEndian>())),
        b'L' => TableEntry::LongLongInt(try!(reader.read_i64::<BigEndian>())),
        b'l' => TableEntry::LongLongUint(try!(reader.read_u64::<BigEndian>())),
        b'f' => TableEntry::Float(try!(reader.read_f32::<BigEndian>())),
        b'd' => TableEntry::Double(try!(reader.read_f64::<BigEndian>())),
        b'D' => {
            TableEntry::DecimalValue(try!(reader.read_u8()), try!(reader.read_u32::<BigEndian>()))
        }
        // b's' => {
        //  let size = try!(reader.read_u8()) as usize;
        // let str =
        // String::from_utf8_lossy(try!(reader.read_exact(size)).as_slice()).to_string();
        //  ShortString(str)
        // },
        b'S' => {
            let size = try!(reader.read_u32::<BigEndian>()) as usize;
            let mut buffer: Vec<u8> = vec![0u8; size];
            try!(reader.read(&mut buffer[..]));
            let str = String::from_utf8_lossy(&buffer).to_string();
            TableEntry::LongString(str)
        }
        b'A' => {
            let size = try!(reader.read_u32::<BigEndian>()) as usize;
            let len_after = reader.len() - size;

            let mut arr = Vec::new();
            while reader.len() > len_after {
                let entry = try!(read_table_entry(reader));
                arr.push(entry)
            }
            TableEntry::FieldArray(arr)
        }
        b'T' => TableEntry::Timestamp(try!(reader.read_u64::<BigEndian>())),
        b'F' => TableEntry::FieldTable(try!(decode_table(reader))),
        b'V' => TableEntry::Void,
        x => {
            debug!("Unknown type: {}", x);
            return Err(AMQPError::DecodeError("Unknown type"));
        }
    };
    Ok(entry)
}

fn write_table_entry(writer: &mut Vec<u8>, table_entry: &TableEntry) -> AMQPResult<()> {
    match *table_entry {
        TableEntry::Bool(val) => {
            try!(writer.write_u8(b't'));
            try!(writer.write_u8(val as u8));
        }
        TableEntry::ShortShortInt(val) => {
            try!(writer.write_u8(b'b'));
            try!(writer.write_i8(val));
        }
        TableEntry::ShortShortUint(val) => {
            try!(writer.write_u8(b'B'));
            try!(writer.write_u8(val));
        }
        TableEntry::ShortInt(val) => {
            try!(writer.write_u8(b'U'));
            try!(writer.write_i16::<BigEndian>(val));
        }
        TableEntry::ShortUint(val) => {
            try!(writer.write_u8(b'u'));
            try!(writer.write_u16::<BigEndian>(val));
        }
        TableEntry::LongInt(val) => {
            try!(writer.write_u8(b'I'));
            try!(writer.write_i32::<BigEndian>(val));
        }
        TableEntry::LongUint(val) => {
            try!(writer.write_u8(b'i'));
            try!(writer.write_u32::<BigEndian>(val));
        }
        TableEntry::LongLongInt(val) => {
            try!(writer.write_u8(b'L'));
            try!(writer.write_i64::<BigEndian>(val));
        }
        TableEntry::LongLongUint(val) => {
            try!(writer.write_u8(b'l'));
            try!(writer.write_u64::<BigEndian>(val));
        }
        TableEntry::Float(val) => {
            try!(writer.write_u8(b'f'));
            try!(writer.write_f32::<BigEndian>(val));
        }
        TableEntry::Double(val) => {
            try!(writer.write_u8(b'd'));
            try!(writer.write_f64::<BigEndian>(val));
        }
        TableEntry::DecimalValue(scale, value) => {
            try!(writer.write_u8(b'D'));
            try!(writer.write_u8(scale));
            try!(writer.write_u32::<BigEndian>(value));
        }
        // ShortString(str) => {
        //  try!(writer.write_u8(b's'));
        //  try!(writer.write_u8(str.len() as u8));
        //  try!(writer.write_all(str.as_bytes()));
        // },
        TableEntry::LongString(ref str) => {
            try!(writer.write_u8(b'S'));
            try!(writer.write_u32::<BigEndian>(str.len() as u32));
            try!(writer.write_all(str.as_bytes()));
        }
        TableEntry::FieldArray(ref arr) => {
            try!(writer.write_u8(b'A'));
            let mut tmp_buffer = vec![];
            for item in arr.iter() {
                try!(write_table_entry(&mut tmp_buffer, item));
            }
            try!(writer.write_u32::<BigEndian>(tmp_buffer.len() as u32));
            try!(writer.write(&tmp_buffer));
        }
        TableEntry::Timestamp(val) => {
            try!(writer.write_u8(b'T'));
            try!(writer.write_u64::<BigEndian>(val))
        }
        TableEntry::FieldTable(ref table) => {
            try!(writer.write_u8(b'F'));
            try!(encode_table(writer, table));
        }
        TableEntry::Void => try!(writer.write_u8(b'V')),
    }
    Ok(())
}

pub fn decode_table(reader: &mut &[u8]) -> AMQPResult<Table> {
    debug!("decoding table");
    let mut table = Table::new();
    let size = try!(reader.read_u32::<BigEndian>()) as usize;
    let total_len = reader.len();

    while reader.len() > total_len - size {
        let field_name_size = try!(reader.read_u8()) as usize;
        let mut field_name: Vec<u8> = vec![0u8; field_name_size];
        try!(reader.read(&mut field_name[..]));
        let table_entry = try!(read_table_entry(reader));
        debug!("Read table entry: {:?} = {:?}", field_name, table_entry);
        table.insert(String::from_utf8_lossy(&field_name).to_string(),
                     table_entry);
    }
    Ok(table)
}

pub fn encode_table<T: Write>(writer: &mut T, table: &Table) -> AMQPResult<()> {
    let mut tmp_buffer = vec![];
    for (field_name, table_entry) in table.iter() {
        try!(tmp_buffer.write_u8(field_name.len() as u8));
        try!(tmp_buffer.write_all(field_name.as_bytes()));
        try!(write_table_entry(&mut tmp_buffer, table_entry));
    }
    try!(writer.write_u32::<BigEndian>(tmp_buffer.len() as u32));
    try!(writer.write_all(&tmp_buffer));
    Ok(())
}
<commit_msg>fixed bad bool reading. close #48 (#49)<commit_after>use std::collections::HashMap;
use amqp_error::{AMQPError, AMQPResult};
use std::io::{Read, Write};
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};

#[derive(Debug, Clone)]
pub enum TableEntry {
    Bool(bool),
    ShortShortInt(i8),
    ShortShortUint(u8),
    ShortInt(i16),
    ShortUint(u16),
    LongInt(i32),
    LongUint(u32),
    LongLongInt(i64),
    LongLongUint(u64),
    Float(f32),
    Double(f64),
    DecimalValue(u8, u32),
    // ShortString(String),
    LongString(String),
    FieldArray(Vec<TableEntry>),
    Timestamp(u64),
    FieldTable(Table),
    Void,
}

pub type Table = HashMap<String, TableEntry>;

pub trait Init {
    fn new() -> Self;
}

impl Init for Table {
    fn new() -> Self {
        HashMap::new()
    }
}

fn read_table_entry(reader: &mut &[u8]) -> AMQPResult<TableEntry> {
    let entry = match try!(reader.read_u8()) {
        b't' => TableEntry::Bool(try!(reader.read_u8()) != 0),
        b'b' => TableEntry::ShortShortInt(try!(reader.read_i8())),
        b'B' => TableEntry::ShortShortUint(try!(reader.read_u8())),
        b'U' => TableEntry::ShortInt(try!(reader.read_i16::<BigEndian>())),
        b'u' => TableEntry::ShortUint(try!(reader.read_u16::<BigEndian>())),
        b'I' => TableEntry::LongInt(try!(reader.read_i32::<BigEndian>())),
        b'i' => TableEntry::LongUint(try!(reader.read_u32::<BigEndian>())),
        b'L' => TableEntry::LongLongInt(try!(reader.read_i64::<BigEndian>())),
        b'l' => TableEntry::LongLongUint(try!(reader.read_u64::<BigEndian>())),
        b'f' => TableEntry::Float(try!(reader.read_f32::<BigEndian>())),
        b'd' => TableEntry::Double(try!(reader.read_f64::<BigEndian>())),
        b'D' => {
            TableEntry::DecimalValue(try!(reader.read_u8()), try!(reader.read_u32::<BigEndian>()))
        }
        // b's' => {
        //  let size = try!(reader.read_u8()) as usize;
        // let str =
        // String::from_utf8_lossy(try!(reader.read_exact(size)).as_slice()).to_string();
        //  ShortString(str)
        // },
        b'S' => {
            let size = try!(reader.read_u32::<BigEndian>()) as usize;
            let mut buffer: Vec<u8> = vec![0u8; size];
            try!(reader.read(&mut buffer[..]));
            let str = String::from_utf8_lossy(&buffer).to_string();
            TableEntry::LongString(str)
        }
        b'A' => {
            let size = try!(reader.read_u32::<BigEndian>()) as usize;
            let len_after = reader.len() - size;

            let mut arr = Vec::new();
            while reader.len() > len_after {
                let entry = try!(read_table_entry(reader));
                arr.push(entry)
            }
            TableEntry::FieldArray(arr)
        }
        b'T' => TableEntry::Timestamp(try!(reader.read_u64::<BigEndian>())),
        b'F' => TableEntry::FieldTable(try!(decode_table(reader))),
        b'V' => TableEntry::Void,
        x => {
            debug!("Unknown type: {}", x);
            return Err(AMQPError::DecodeError("Unknown type"));
        }
    };
    Ok(entry)
}

fn write_table_entry(writer: &mut Vec<u8>, table_entry: &TableEntry) -> AMQPResult<()> {
    match *table_entry {
        TableEntry::Bool(val) => {
            try!(writer.write_u8(b't'));
            try!(writer.write_u8(val as u8));
        }
        TableEntry::ShortShortInt(val) => {
            try!(writer.write_u8(b'b'));
            try!(writer.write_i8(val));
        }
        TableEntry::ShortShortUint(val) => {
            try!(writer.write_u8(b'B'));
            try!(writer.write_u8(val));
        }
        TableEntry::ShortInt(val) => {
            try!(writer.write_u8(b'U'));
            try!(writer.write_i16::<BigEndian>(val));
        }
        TableEntry::ShortUint(val) => {
            try!(writer.write_u8(b'u'));
            try!(writer.write_u16::<BigEndian>(val));
        }
        TableEntry::LongInt(val) => {
            try!(writer.write_u8(b'I'));
            try!(writer.write_i32::<BigEndian>(val));
        }
        TableEntry::LongUint(val) => {
            try!(writer.write_u8(b'i'));
            try!(writer.write_u32::<BigEndian>(val));
        }
        TableEntry::LongLongInt(val) => {
            try!(writer.write_u8(b'L'));
            try!(writer.write_i64::<BigEndian>(val));
        }
        TableEntry::LongLongUint(val) => {
            try!(writer.write_u8(b'l'));
            try!(writer.write_u64::<BigEndian>(val));
        }
        TableEntry::Float(val) => {
            try!(writer.write_u8(b'f'));
            try!(writer.write_f32::<BigEndian>(val));
        }
        TableEntry::Double(val) => {
            try!(writer.write_u8(b'd'));
            try!(writer.write_f64::<BigEndian>(val));
        }
        TableEntry::DecimalValue(scale, value) => {
            try!(writer.write_u8(b'D'));
            try!(writer.write_u8(scale));
            try!(writer.write_u32::<BigEndian>(value));
        }
        // ShortString(str) => {
        //  try!(writer.write_u8(b's'));
        //  try!(writer.write_u8(str.len() as u8));
        //  try!(writer.write_all(str.as_bytes()));
        // },
        TableEntry::LongString(ref str) => {
            try!(writer.write_u8(b'S'));
            try!(writer.write_u32::<BigEndian>(str.len() as u32));
            try!(writer.write_all(str.as_bytes()));
        }
        TableEntry::FieldArray(ref arr) => {
            try!(writer.write_u8(b'A'));
            let mut tmp_buffer = vec![];
            for item in arr.iter() {
                try!(write_table_entry(&mut tmp_buffer, item));
            }
            try!(writer.write_u32::<BigEndian>(tmp_buffer.len() as u32));
            try!(writer.write(&tmp_buffer));
        }
        TableEntry::Timestamp(val) => {
            try!(writer.write_u8(b'T'));
            try!(writer.write_u64::<BigEndian>(val))
        }
        TableEntry::FieldTable(ref table) => {
            try!(writer.write_u8(b'F'));
            try!(encode_table(writer, table));
        }
        TableEntry::Void => try!(writer.write_u8(b'V')),
    }
    Ok(())
}

pub fn decode_table(reader: &mut &[u8]) -> AMQPResult<Table> {
    debug!("decoding table");
    let mut table = Table::new();
    let size = try!(reader.read_u32::<BigEndian>()) as usize;
    let total_len = reader.len();

    while reader.len() > total_len - size {
        let field_name_size = try!(reader.read_u8()) as usize;
        let mut field_name: Vec<u8> = vec![0u8; field_name_size];
        try!(reader.read(&mut field_name[..]));
        let table_entry = try!(read_table_entry(reader));
        debug!("Read table entry: {:?} = {:?}", field_name, table_entry);
        table.insert(String::from_utf8_lossy(&field_name).to_string(),
                     table_entry);
    }
    Ok(table)
}

pub fn encode_table<T: Write>(writer: &mut T, table: &Table) -> AMQPResult<()> {
    let mut tmp_buffer = vec![];
    for (field_name, table_entry) in table.iter() {
        try!(tmp_buffer.write_u8(field_name.len() as u8));
        try!(tmp_buffer.write_all(field_name.as_bytes()));
        try!(write_table_entry(&mut tmp_buffer, table_entry));
    }
    try!(writer.write_u32::<BigEndian>(tmp_buffer.len() as u32));
    try!(writer.write_all(&tmp_buffer));
    Ok(())
}
<|endoftext|>


<commit_before>use super::*;

#[test]
fn sliding_windows_1() {
    fn test_window_correctness_with_storage(mut storage: Storage<u32>) {
        let expected: &[&[u32]] = &[&[0,1,2], &[1,2,3], &[2,3,4]];

        {
            let windowed_iter = Adaptor::new(0..5, &mut storage);
            let output: Vec<Vec<u32>> = windowed_iter.map(|x| From::from(&x[..])).collect();
            assert_eq!(output, expected);
        }
    }

    let auto_alloc:   Storage<u32> = Storage::optimized(&(0..5), 3);
    let middle_alloc: Storage<u32> = Storage::new(3);
    let small_alloc:  Storage<u32> = Storage::from_vec(vec![1u32;   1], 3);
    let exact_alloc:  Storage<u32> = Storage::from_vec(vec![1u32;   3], 3);
    let big_alloc:    Storage<u32> = Storage::from_vec(vec![1u32, 100], 3);

    test_window_correctness_with_storage(auto_alloc);
    test_window_correctness_with_storage(middle_alloc);
    test_window_correctness_with_storage(small_alloc);
    test_window_correctness_with_storage(exact_alloc);
    test_window_correctness_with_storage(big_alloc);
}

#[test]
fn sliding_windows_2() {
    let it = 0..5;
    let mut storage: Storage<u32> = Storage::optimized(&it, 3);
    let windowed_iter = Adaptor::new(it, &mut storage);

    for mut x in windowed_iter {
        x[1] = 0u32;
        assert_eq!(x[0], 0);
    }
}

#[test]
#[should_panic]
fn sliding_windows_3() {
    let it = 0..5;
    let mut storage: Storage<u32> = Storage::optimized(&it, 3);
    let mut windowed_iter = Adaptor::new(it, &mut storage);

    let _a = windowed_iter.next();
    let _b = windowed_iter.next();
}

#[test]
fn sliding_windows_4() {
    let mut storage1: Storage<u32> = Storage::new(3);
    let iter1 = Adaptor::new(0..5, &mut storage1);

    let mut storage2: Storage<u32> = Storage::new(5);
    let iter2 = Adaptor::new(0..5, &mut storage2);

    let mut storage3: Storage<u32> = Storage::new(6);
    let iter3 = Adaptor::new(0..5, &mut storage3);

    let mut storage4: Storage<u32> = Storage::new(6);
    let iter4 = Adaptor::new(42..42, &mut storage4);

    let mut storage5: Storage<u32> = Storage::new(6);
    let iter5 = Adaptor::new(42.., &mut storage5);

    assert_eq!(iter1.size_hint(), (3, Some(3)));
    assert_eq!(iter2.size_hint(), (1, Some(1)));
    assert_eq!(iter3.size_hint(), (1, Some(1)));
    assert_eq!(iter4.size_hint(), (0, Some(0)));
    assert_eq!(iter5.size_hint().1, None);
}

#[test]
fn sliding_windows_5() {
    let range = 0..5;
    let mut storage: Storage<u32> = Storage::optimized(&range, 0);
    let mut iter = Adaptor::new(range, &mut storage);

    assert!(iter.next().is_none());
    assert!(iter.next().is_none());
}

#[test]
fn sliding_windows_6() {
    let range0 = 0..0;
    let range1 = 0..1;
    let range2 = 0..2;

    let storage0: Storage<u32> = Storage::optimized(&range0, 1);
    let storage0: Vec<u32> = storage0.into();
    assert_eq!(storage0.capacity(), 2);

    let storage1: Storage<u32> = Storage::optimized(&range1, 1);
    let storage1: Vec<u32> = storage1.into();
    assert_eq!(storage1.capacity(), 1);

    let storage2: Storage<u32> = Storage::optimized(&range2, 1);
    let storage2: Vec<u32> = storage2.into();
    assert_eq!(storage2.capacity(), 2);

    let storage3: Storage<u32> = Storage::optimized(&range2, 3);
    let storage3: Vec<u32> = storage3.into();
    assert_eq!(storage3.capacity(), 2);
}
<commit_msg>implement tests for new api remove a few unnecessary tests ignore 1 test (mutable window), which is not implemented yet<commit_after>use super::*;

#[test]
fn sliding_windows_1() {
    fn test_window_correctness_with_storage(mut storage: Storage<u32>) {
        let expected: &[&[u32]] = &[&[0,1,2], &[1,2,3], &[2,3,4]];

        {
            let windowed_iter = Adaptor::new(0..5, &mut storage);
            let output: Vec<Vec<u32>> = windowed_iter.map(|x| {
                println!("{:?}", x);
                x.into_iter().map(|&x| x).collect()
            }).collect();
            assert_eq!(output, expected);
        }
    }

    let middle_alloc: Storage<u32> = Storage::new(3);
    let small_alloc:  Storage<u32> = Storage::from_vec(vec![1u32;   1], 3);
    let exact_alloc:  Storage<u32> = Storage::from_vec(vec![1u32;   3], 3);
    let big_alloc:    Storage<u32> = Storage::from_vec(vec![1u32, 100], 3);

    test_window_correctness_with_storage(middle_alloc);
    test_window_correctness_with_storage(small_alloc);
    test_window_correctness_with_storage(exact_alloc);
    test_window_correctness_with_storage(big_alloc);
}

#[test]
#[ignore]
fn sliding_windows_2() {
    let it = 0..5;
    let mut storage: Storage<u32> = Storage::new(3);
    let windowed_iter = Adaptor::new(it, &mut storage);

    for mut x in windowed_iter {
        // TODO reenable x[1] = 0u32;
        // TODO reenable assert_eq!(x[0], 0);
    }
}

#[test]
#[should_panic]
fn sliding_windows_3() {
    let it = 0..5;
    let mut storage: Storage<u32> = Storage::new(3);
    let mut windowed_iter = Adaptor::new(it, &mut storage);

    let _a = windowed_iter.next();
    let _b = windowed_iter.next();
}

#[test]
fn sliding_windows_4() {
    let mut storage1: Storage<u32> = Storage::new(3);
    let iter1 = Adaptor::new(0..5, &mut storage1);

    let mut storage2: Storage<u32> = Storage::new(5);
    let iter2 = Adaptor::new(0..5, &mut storage2);

    let mut storage3: Storage<u32> = Storage::new(6);
    let iter3 = Adaptor::new(0..5, &mut storage3);

    let mut storage4: Storage<u32> = Storage::new(6);
    let iter4 = Adaptor::new(42..42, &mut storage4);

    let mut storage5: Storage<u32> = Storage::new(6);
    let iter5 = Adaptor::new(42.., &mut storage5);

    assert_eq!(iter1.size_hint(), (3, Some(3)));
    assert_eq!(iter2.size_hint(), (1, Some(1)));
    assert_eq!(iter3.size_hint(), (1, Some(1)));
    assert_eq!(iter4.size_hint(), (0, Some(0)));
    assert_eq!(iter5.size_hint().1, None);
}

#[test]
fn sliding_windows_5() {
    let range = 0..5;
    let mut storage: Storage<u32> = Storage::new(0);
    let mut iter = Adaptor::new(range, &mut storage);

    assert!(iter.next().is_none());
    assert!(iter.next().is_none());
}

#[test]
fn sliding_windows_6() {
    let storage0: Storage<u32> = Storage::new(0);
    let storage0: Vec<u32> = storage0.into();
    assert_eq!(storage0.capacity(), 0);

    let storage1: Storage<u32> = Storage::new(12);
    let storage1: Vec<u32> = storage1.into();
    assert_eq!(storage1.capacity(), 12);

    let storage2: Storage<u32> = Storage::new(20);
    let storage2: Vec<u32> = storage2.into();
    assert_eq!(storage2.capacity(), 20);
}
<|endoftext|>


<commit_before>use crate::{BlockingRecv, BlockingSend, Socket, SocketFrontend};
use std::convert::TryInto;
use std::error::Error;
use std::time::Duration;

#[tokio::test]
async fn test_pub_sub_sockets() {
    tokio::spawn(async move {
        let mut pub_socket = crate::PubSocket::new();
        pub_socket
            .bind("127.0.0.1:5556")
            .await
            .expect("Failed to bind socket");

        for i in 0..10i32 {
            let message = format!("Message - {}", i);
            pub_socket
                .send(message.into())
                .await
                .expect("Failed to send");
        }
    });

    tokio::spawn(async move {
        let mut sub_socket = crate::SubSocket::connect("127.0.0.1:5556")
            .await
            .expect("Failed to connect");

        sub_socket.subscribe("").await.expect("Failed to subscribe");

        for i in 0..10i32 {
            let repl: String = sub_socket
                .recv()
                .await
                .expect("Failed to recv")
                .try_into()
                .expect("Malformed string");
            assert_eq!(format!("Message - {}", i), repl)
        }
    });
}

async fn run_rep_server() -> Result<(), Box<dyn Error>> {
    let mut rep_socket = crate::RepSocket::new();
    rep_socket.bind("127.0.0.1:5557").await?;
    println!("Started rep server on 127.0.0.1:5557");

    for i in 0..10i32 {
        let mess: String = rep_socket.recv().await?.try_into()?;
        rep_socket
            .send(format!("{} Rep - {}", mess, i).into())
            .await?;
    }
    Ok(())
}

#[tokio::test]
async fn test_req_rep_sockets() -> Result<(), Box<dyn Error>> {
    tokio::spawn(async move {
        run_rep_server().await.unwrap();
    });

    // yield for a moment to ensure that server has some time to open socket
    tokio::time::delay_for(Duration::from_millis(10)).await;
    let mut req_socket = crate::ReqSocket::new();
    req_socket.connect("127.0.0.1:5557").await?;
    println!("Connected to server");

    for i in 0..10i32 {
        req_socket.send(format!("Req - {}", i).into()).await?;
        let repl: String = req_socket.recv().await?.try_into()?;
        assert_eq!(format!("Req - {} Rep - {}", i, i), repl)
    }
    Ok(())
}
<commit_msg>Added test to check that many req sockets work correctly<commit_after>use crate::{BlockingRecv, BlockingSend, Socket, SocketFrontend};
use std::convert::TryInto;
use std::error::Error;
use std::time::Duration;

#[tokio::test]
async fn test_pub_sub_sockets() {
    tokio::spawn(async move {
        let mut pub_socket = crate::PubSocket::new();
        pub_socket
            .bind("127.0.0.1:5556")
            .await
            .expect("Failed to bind socket");

        for i in 0..10i32 {
            let message = format!("Message - {}", i);
            pub_socket
                .send(message.into())
                .await
                .expect("Failed to send");
        }
    });

    tokio::spawn(async move {
        let mut sub_socket = crate::SubSocket::connect("127.0.0.1:5556")
            .await
            .expect("Failed to connect");

        sub_socket.subscribe("").await.expect("Failed to subscribe");

        for i in 0..10i32 {
            let repl: String = sub_socket
                .recv()
                .await
                .expect("Failed to recv")
                .try_into()
                .expect("Malformed string");
            assert_eq!(format!("Message - {}", i), repl)
        }
    });
}

async fn run_rep_server() -> Result<(), Box<dyn Error>> {
    let mut rep_socket = crate::RepSocket::new();
    rep_socket.bind("127.0.0.1:5557").await?;
    println!("Started rep server on 127.0.0.1:5557");

    for i in 0..10i32 {
        let mess: String = rep_socket.recv().await?.try_into()?;
        rep_socket
            .send(format!("{} Rep - {}", mess, i).into())
            .await?;
    }
    Ok(())
}

#[tokio::test]
async fn test_req_rep_sockets() -> Result<(), Box<dyn Error>> {
    tokio::spawn(async move {
        run_rep_server().await.unwrap();
    });

    // yield for a moment to ensure that server has some time to open socket
    tokio::time::delay_for(Duration::from_millis(10)).await;
    let mut req_socket = crate::ReqSocket::new();
    req_socket.connect("127.0.0.1:5557").await?;
    println!("Connected to server");

    for i in 0..10i32 {
        req_socket.send(format!("Req - {}", i).into()).await?;
        let repl: String = req_socket.recv().await?.try_into()?;
        assert_eq!(format!("Req - {} Rep - {}", i, i), repl)
    }
    Ok(())
}

#[tokio::test]
async fn test_many_req_rep_sockets() -> Result<(), Box<dyn Error>> {
    for i in 0..100i32 {
        tokio::spawn(async move {
            // yield for a moment to ensure that server has some time to open socket
            tokio::time::delay_for(Duration::from_millis(100)).await;
            let mut req_socket = crate::ReqSocket::new();
            req_socket.connect("127.0.0.1:5558").await.unwrap();
            println!("Connected to server");

            for i in 0..100i32 {
                req_socket
                    .send(format!("Req - {}", i).into())
                    .await
                    .unwrap();
                let repl: String = req_socket.recv().await.unwrap().try_into().unwrap();
                assert_eq!(format!("Req - {} Rep", i), repl)
            }
        });
    }

    let mut rep_socket = crate::RepSocket::new();
    rep_socket.bind("127.0.0.1:5558").await?;
    println!("Started rep server on 127.0.0.1:5558");

    for i in 0..10000i32 {
        let mess: String = rep_socket.recv().await?.try_into()?;
        rep_socket.send(format!("{} Rep", mess).into()).await?;
    }
    Ok(())
}
<|endoftext|>


<commit_before>#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct Token(pub usize);

use slab;

impl Token {
    #[inline]
    pub fn as_usize(self) -> usize {
        let Token(inner) = self;
        inner
    }
}

impl slab::Index for Token {
    fn from_usize(i: usize) -> Token {
        Token(i)
    }

    fn as_usize(&self) -> usize {
        Token::as_usize(*self)
    }
}
<commit_msg>Token now derives PartialOrd, Ord. Closes #263.<commit_after>#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Token(pub usize);

use slab;

impl Token {
    #[inline]
    pub fn as_usize(self) -> usize {
        let Token(inner) = self;
        inner
    }
}

impl slab::Index for Token {
    fn from_usize(i: usize) -> Token {
        Token(i)
    }

    fn as_usize(&self) -> usize {
        Token::as_usize(*self)
    }
}
<|endoftext|>


<commit_before>extern crate c_ares_sys;
extern crate libc;

use std::net::{Ipv4Addr, Ipv6Addr};
use std::os::unix::io;

/// Flags that may be passed when initializing a channel.
#[derive(Debug, Clone, Copy)]
pub enum Flag {
    /// Always use TCP queries (the "virtual circuit") instead of UDP queries.
    /// Normally, TCP is only used if a UDP query yields a truncated result.
    USEVC = c_ares_sys::ARES_FLAG_USEVC as isize,

    /// Only query the first server in the list of servers to query.
    PRIMARY = c_ares_sys::ARES_FLAG_PRIMARY as isize,

    /// If a truncated response to a UDP query is received, do not fall back
    /// to TCP; simply continue on with the truncated response.
    IGNTC = c_ares_sys::ARES_FLAG_IGNTC as isize,

    /// Do not set the "recursion desired" bit on outgoing queries, so that
    /// the name server being contacted will not try to fetch the answer from
    /// other servers if it doesn't know the answer locally.
    NORECURSE = c_ares_sys::ARES_FLAG_NORECURSE as isize,

    /// Do not close communications sockets when the number of active queries
    /// drops to zero.
    STAYOPEN = c_ares_sys::ARES_FLAG_STAYOPEN as isize,

    /// Do not use the default search domains; only query hostnames as-is or as
    /// aliases.
    NOSEARCH = c_ares_sys::ARES_FLAG_NOSEARCH as isize,

    /// Do not honor the HOSTALIASES environment variable, which normally
    /// specifies a file of hostname translations.
    NOALIASES = c_ares_sys::ARES_FLAG_NOALIASES as isize,

    /// Do not discard responses with the SERVFAIL, NOTIMP, or REFUSED response
    /// code or responses whose questions don't match the questions in the
    /// request. Primarily useful for writing clients which might be used to
    /// test or debug name servers.
    NOCHECKRESP = c_ares_sys::ARES_FLAG_NOCHECKRESP as isize,
    EDNS = c_ares_sys::ARES_FLAG_EDNS as isize,
}

/// An invalid file descriptor.  Use this to represent 'no action' when calling
/// `process_fd()` on a channel.
pub const INVALID_FD: io::RawFd = c_ares_sys::ARES_SOCKET_BAD as io::RawFd;

/// Error codes that the library might return.  Use `str_error()` to convert an
/// error code into a description.
#[derive(Debug, Clone, Copy)]
pub enum AresError {
    ENODATA = 1,
    EFORMERR,
    ESERVFAIL,
    ENOTFOUND,
    ENOTIMP,
    EREFUSED,
    EBADQUERY,
    EBADNAME,
    EBADFAMILY,
    EBADRESP,
    ECONNREFUSED,
    ETIMEOUT,
    EOF,
    EFILE,
    ENOMEM,
    EDESTRUCTION,
    EBADSTR,
    EBADFLAGS,
    ENONAME,
    EBADHINTS,
    ENOTINITIALIZED,
    ELOADIPHLPAPI,
    EADDRGETNETWORKPARAMS,
    ECANCELLED,
    UNKNOWN,
}

/// The result of a successful lookup for an A record.
#[derive(Debug, Clone)]
pub struct AResult {
    /// The IP addresses returned by the lookup.
    pub ip_addrs: Vec<Ipv4Addr>,
}

/// The result of a successful lookup for an AAAA record.
#[derive(Debug, Clone)]
pub struct AAAAResult {
    /// The IP addresses returned by the lookup.
    pub ip_addrs: Vec<Ipv6Addr>,
}

#[repr(C)]
pub struct hostent {
    pub h_name: *mut libc::c_char,
    pub h_aliases: *mut *mut libc::c_char,
    pub h_addrtype: libc::c_int,
    pub h_length: libc::c_int,
    pub h_addr_list: *mut *mut libc::c_char,
}

// See arpa/nameser.h
pub enum QueryType {
    A = 1,
    AAAA = 28,
}

// See arpa/nameser.h
pub enum DnsClass {
   IN = 1,
}
<commit_msg>Explicitly match exposed constants to c-ares values<commit_after>extern crate c_ares_sys;
extern crate libc;

use std::net::{Ipv4Addr, Ipv6Addr};
use std::os::unix::io;

/// Flags that may be passed when initializing a channel.
#[derive(Debug, Clone, Copy)]
pub enum Flag {
    /// Always use TCP queries (the "virtual circuit") instead of UDP queries.
    /// Normally, TCP is only used if a UDP query yields a truncated result.
    USEVC = c_ares_sys::ARES_FLAG_USEVC as isize,

    /// Only query the first server in the list of servers to query.
    PRIMARY = c_ares_sys::ARES_FLAG_PRIMARY as isize,

    /// If a truncated response to a UDP query is received, do not fall back
    /// to TCP; simply continue on with the truncated response.
    IGNTC = c_ares_sys::ARES_FLAG_IGNTC as isize,

    /// Do not set the "recursion desired" bit on outgoing queries, so that
    /// the name server being contacted will not try to fetch the answer from
    /// other servers if it doesn't know the answer locally.
    NORECURSE = c_ares_sys::ARES_FLAG_NORECURSE as isize,

    /// Do not close communications sockets when the number of active queries
    /// drops to zero.
    STAYOPEN = c_ares_sys::ARES_FLAG_STAYOPEN as isize,

    /// Do not use the default search domains; only query hostnames as-is or as
    /// aliases.
    NOSEARCH = c_ares_sys::ARES_FLAG_NOSEARCH as isize,

    /// Do not honor the HOSTALIASES environment variable, which normally
    /// specifies a file of hostname translations.
    NOALIASES = c_ares_sys::ARES_FLAG_NOALIASES as isize,

    /// Do not discard responses with the SERVFAIL, NOTIMP, or REFUSED response
    /// code or responses whose questions don't match the questions in the
    /// request. Primarily useful for writing clients which might be used to
    /// test or debug name servers.
    NOCHECKRESP = c_ares_sys::ARES_FLAG_NOCHECKRESP as isize,
    EDNS = c_ares_sys::ARES_FLAG_EDNS as isize,
}

/// An invalid file descriptor.  Use this to represent 'no action' when calling
/// `process_fd()` on a channel.
pub const INVALID_FD: io::RawFd = c_ares_sys::ARES_SOCKET_BAD as io::RawFd;

/// Error codes that the library might return.  Use `str_error()` to convert an
/// error code into a description.
#[derive(Debug, Clone, Copy)]
pub enum AresError {
    ENODATA = c_ares_sys::ARES_ENODATA as isize,
    EFORMERR = c_ares_sys::ARES_EFORMERR  as isize,
    ESERVFAIL = c_ares_sys::ARES_ESERVFAIL as isize,
    ENOTFOUND = c_ares_sys::ARES_ENOTFOUND as isize,
    ENOTIMP = c_ares_sys::ARES_ENOTIMP as isize,
    EREFUSED = c_ares_sys::ARES_EREFUSED as isize,
    EBADQUERY = c_ares_sys::ARES_EBADQUERY as isize,
    EBADNAME = c_ares_sys::ARES_EBADNAME as isize,
    EBADFAMILY = c_ares_sys::ARES_EBADFAMILY as isize,
    EBADRESP = c_ares_sys::ARES_EBADRESP as isize,
    ECONNREFUSED = c_ares_sys::ARES_ECONNREFUSED as isize,
    ETIMEOUT = c_ares_sys::ARES_ETIMEOUT as isize,
    EOF = c_ares_sys::ARES_EOF as isize,
    EFILE = c_ares_sys::ARES_EFILE as isize,
    ENOMEM = c_ares_sys::ARES_ENOMEM as isize,
    EDESTRUCTION = c_ares_sys::ARES_EDESTRUCTION as isize,
    EBADSTR = c_ares_sys::ARES_EBADSTR as isize,
    EBADFLAGS = c_ares_sys::ARES_EBADFLAGS as isize,
    ENONAME = c_ares_sys::ARES_ENONAME as isize,
    EBADHINTS = c_ares_sys::ARES_EBADHINTS as isize,
    ENOTINITIALIZED = c_ares_sys::ARES_ENOTINITIALIZED as isize,
    ELOADIPHLPAPI = c_ares_sys::ARES_ELOADIPHLPAPI as isize,
    EADDRGETNETWORKPARAMS = c_ares_sys::ARES_EADDRGETNETWORKPARAMS as isize,
    ECANCELLED = c_ares_sys::ARES_ECANCELLED as isize,
    UNKNOWN,
}

/// The result of a successful lookup for an A record.
#[derive(Debug, Clone)]
pub struct AResult {
    /// The IP addresses returned by the lookup.
    pub ip_addrs: Vec<Ipv4Addr>,
}

/// The result of a successful lookup for an AAAA record.
#[derive(Debug, Clone)]
pub struct AAAAResult {
    /// The IP addresses returned by the lookup.
    pub ip_addrs: Vec<Ipv6Addr>,
}

#[repr(C)]
pub struct hostent {
    pub h_name: *mut libc::c_char,
    pub h_aliases: *mut *mut libc::c_char,
    pub h_addrtype: libc::c_int,
    pub h_length: libc::c_int,
    pub h_addr_list: *mut *mut libc::c_char,
}

// See arpa/nameser.h
pub enum QueryType {
    A = 1,
    AAAA = 28,
}

// See arpa/nameser.h
pub enum DnsClass {
   IN = 1,
}
<|endoftext|>


<commit_before>// Copyright 2015-2016, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use ffi;
use translate::*;

/// Same as [`get_prgname()`].
///
/// [`get_prgname()`]: fn.get_prgname.html
pub fn get_program_name() -> Option<String> {
    get_prgname()
}

pub fn get_prgname() -> Option<String> {
    unsafe {
        from_glib_none(ffi::g_get_prgname())
    }
}

/// Same as [`set_prgname()`].
///
/// [`set_prgname()`]: fn.set_prgname.html
pub fn set_program_name(name: Option<&str>) {
    set_prgname(name)
}

pub fn set_prgname(name: Option<&str>) {
    unsafe {
        ffi::g_set_prgname(name.to_glib_none().0)
    }
}

#[cfg(not(windows))]
pub fn getenv(variable_name: &str) -> Option<String> {
    unsafe {
        from_glib_none(ffi::g_getenv(variable_name.to_glib_none().0))
    }
}

#[cfg(windows)]
pub fn getenv(variable_name: &str) -> Option<String> {
    use libc::c_char;
    extern "C" {
        fn g_getenv_utf8(variable: *const c_char) -> *const c_char;
    }

    unsafe {
        from_glib_none(g_getenv_utf8(variable_name.to_glib_none().0))
    }
}

#[cfg(not(windows))]
pub fn setenv(variable_name: &str, value: &str, overwrite: bool) -> bool {
    unsafe {
        from_glib(ffi::g_setenv(variable_name.to_glib_none().0,
                                value.to_glib_none().0,
                                overwrite.to_glib()))
    }
}

#[cfg(windows)]
pub fn setenv(variable_name: &str, value: &str, overwrite: bool) -> bool {
    use libc::c_char;
    extern "C" {
        fn g_setenv_utf8(variable: *const c_char, value: *const c_char, overwrite: ffi::gboolean) -> ffi::gboolean;
    }

    unsafe {
        from_glib(g_setenv_utf8(variable_name.to_glib_none().0,
                                value.to_glib_none().0,
                                overwrite.to_glib()))
    }
}

#[cfg(not(windows))]
pub fn unsetenv(variable_name: &str) {
    unsafe {
        ffi::g_unsetenv(variable_name.to_glib_none().0)
    }
}

#[cfg(windows)]
pub fn unsetenv(variable_name: &str) {
    use libc::c_char;
    extern "C" {
        fn g_unsetenv_utf8(variable: *const c_char);
    }

    unsafe {
        g_unsetenv_utf8(variable_name.to_glib_none().0)
    }
}

pub fn get_user_name() -> Option<String> {
    unsafe {
        from_glib_none(ffi::g_get_user_name())
    }
}

#[cfg(not(windows))]
pub fn get_current_dir() -> Option<String> {
    unsafe {
        from_glib_none(ffi::g_get_current_dir())
    }
}

#[cfg(windows)]
pub fn get_current_dir() -> Option<String> {
    use libc::c_char;
    extern "C" {
        fn g_get_current_dir_utf8() -> *mut c_char;
    }

    unsafe {
        from_glib_none(g_get_current_dir_utf8())
    }
}
<commit_msg>g_get_current_dir() returns a string that is to be freed after usage<commit_after>// Copyright 2015-2016, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use ffi;
use translate::*;

/// Same as [`get_prgname()`].
///
/// [`get_prgname()`]: fn.get_prgname.html
pub fn get_program_name() -> Option<String> {
    get_prgname()
}

pub fn get_prgname() -> Option<String> {
    unsafe {
        from_glib_none(ffi::g_get_prgname())
    }
}

/// Same as [`set_prgname()`].
///
/// [`set_prgname()`]: fn.set_prgname.html
pub fn set_program_name(name: Option<&str>) {
    set_prgname(name)
}

pub fn set_prgname(name: Option<&str>) {
    unsafe {
        ffi::g_set_prgname(name.to_glib_none().0)
    }
}

#[cfg(not(windows))]
pub fn getenv(variable_name: &str) -> Option<String> {
    unsafe {
        from_glib_none(ffi::g_getenv(variable_name.to_glib_none().0))
    }
}

#[cfg(windows)]
pub fn getenv(variable_name: &str) -> Option<String> {
    use libc::c_char;
    extern "C" {
        fn g_getenv_utf8(variable: *const c_char) -> *const c_char;
    }

    unsafe {
        from_glib_none(g_getenv_utf8(variable_name.to_glib_none().0))
    }
}

#[cfg(not(windows))]
pub fn setenv(variable_name: &str, value: &str, overwrite: bool) -> bool {
    unsafe {
        from_glib(ffi::g_setenv(variable_name.to_glib_none().0,
                                value.to_glib_none().0,
                                overwrite.to_glib()))
    }
}

#[cfg(windows)]
pub fn setenv(variable_name: &str, value: &str, overwrite: bool) -> bool {
    use libc::c_char;
    extern "C" {
        fn g_setenv_utf8(variable: *const c_char, value: *const c_char, overwrite: ffi::gboolean) -> ffi::gboolean;
    }

    unsafe {
        from_glib(g_setenv_utf8(variable_name.to_glib_none().0,
                                value.to_glib_none().0,
                                overwrite.to_glib()))
    }
}

#[cfg(not(windows))]
pub fn unsetenv(variable_name: &str) {
    unsafe {
        ffi::g_unsetenv(variable_name.to_glib_none().0)
    }
}

#[cfg(windows)]
pub fn unsetenv(variable_name: &str) {
    use libc::c_char;
    extern "C" {
        fn g_unsetenv_utf8(variable: *const c_char);
    }

    unsafe {
        g_unsetenv_utf8(variable_name.to_glib_none().0)
    }
}

pub fn get_user_name() -> Option<String> {
    unsafe {
        from_glib_none(ffi::g_get_user_name())
    }
}

#[cfg(not(windows))]
pub fn get_current_dir() -> Option<String> {
    unsafe {
        from_glib_full(ffi::g_get_current_dir())
    }
}

#[cfg(windows)]
pub fn get_current_dir() -> Option<String> {
    use libc::c_char;
    extern "C" {
        fn g_get_current_dir_utf8() -> *mut c_char;
    }

    unsafe {
        from_glib_full(g_get_current_dir_utf8())
    }
}
<|endoftext|>


<commit_before>//! Utils to test with testing and debugging.

use image::{
    DynamicImage,
    GenericImage,
    GrayImage,
    Luma,
    open,
    Pixel,
    Rgb,
    RgbImage
};

use std::fmt::Debug;
use std::path::Path;

/// Panics if any pixels differ between the two input images.
#[macro_export]
macro_rules! assert_pixels_eq {
    ($actual:expr, $expected:expr) => ({
        assert_dimensions_match!($actual, $expected);
        let diffs = $crate::utils::pixel_diffs(&$actual, &$expected, |p, q| p != q);
        if !diffs.is_empty() {
            panic!($crate::utils::describe_pixel_diffs(diffs.into_iter()))
        }
     })
}

/// Panics if any pixels differ between the two images by more than the
/// given tolerance in a single channel.
#[macro_export]
macro_rules! assert_pixels_eq_within {
    ($actual:expr, $expected:expr, $channel_tolerance:expr) => ({

        assert_dimensions_match!($actual, $expected);
        let diffs = $crate::utils::pixel_diffs(&$actual, &$expected, |p, q| {

            use image::Pixel;
            let cp = p.2.channels();
            let cq = q.2.channels();
            if cp.len() != cq.len() {
                panic!("pixels have different channel counts. \
                    actual: {:?}, expected: {:?}", cp.len(), cq.len())
            }

            let mut large_diff = false;
            for i in 0..cp.len() {
                let sp = cp[i];
                let sq = cq[i];
                // Handle unsigned subpixels
                let diff = if sp > sq {sp - sq} else {sq - sp};
                if diff > $channel_tolerance {
                    large_diff = true;
                    break;
                }
            }

            large_diff
        });
        if !diffs.is_empty() {
            panic!($crate::utils::describe_pixel_diffs(diffs.into_iter()))
        }
    })
}

#[macro_export]
macro_rules! assert_dimensions_match {
    ($actual:expr, $expected:expr) => ({

        let actual_dim = $actual.dimensions();
        let expected_dim = $expected.dimensions();

        if actual_dim != expected_dim {
            panic!("dimensions do not match. \
                actual: {:?}, expected: {:?}", actual_dim, expected_dim)
        }
     })
}

/// Lists pixels that differ between left and right images.
pub fn pixel_diffs<I, F>(left: &I, right: &I, is_diff: F)
        -> Vec<((u32, u32, I::Pixel), (u32, u32, I::Pixel))>
    where I: GenericImage,
          I::Pixel: PartialEq,
          F: Fn((u32, u32, I::Pixel), (u32, u32, I::Pixel)) -> bool {

    // Can't just call $image.pixels(), as that needn't hit the
    // trait pixels method - ImageBuffer defines its own pixels
    // method with a different signature
    GenericImage::pixels(left)
        .zip(GenericImage::pixels(right))
        .filter(|&(p, q)| is_diff(p, q))//p != q)
        .collect::<Vec<_>>()
}

/// Gives a summary description of a list of pixel diffs for use in error messages.
pub fn describe_pixel_diffs<I, P>(diffs: I) -> String
    where I: Iterator<Item=(P, P)>,
          P: Debug {

    let mut err = "pixels do not match. ".to_string();
    err.push_str(&(diffs
        .take(5)
        .map(|d| format!("\nactual: {:?}, expected {:?} ", d.0, d.1))
        .collect::<Vec<_>>()
        .join("")));
    err
}

/// Loads image at given path, panicking on failure.
pub fn load_image_or_panic(path: &Path) -> DynamicImage {
     open(path)
         .ok()
         .expect(&format!("Could not load image at {:?}", path))
}

/// Gray image to use in benchmarks. This is neither noise nor
/// similar to natural images - it's just a convenience method
/// to produce an image that's not constant.
pub fn gray_bench_image(width: u32, height: u32) -> GrayImage {
    let mut image = GrayImage::new(width, height);
    for y in 0..image.height() {
        for x in 0..image.width() {
            let intensity = (x % 7 + y % 6) as u8;
            image.put_pixel(x, y, Luma([intensity]));
        }
    }
    image
}

/// RGB image to use in benchmarks. See comment on gray_bench_image.
pub fn rgb_bench_image(width: u32, height: u32) -> RgbImage {
    use std::cmp;
    let mut image = RgbImage::new(width, height);
    for y in 0..image.height() {
        for x in 0..image.width() {
            let r = (x % 7 + y % 6) as u8;
            let g = 255u8 - r;
            let b = cmp::min(r, g);
            image.put_pixel(x, y, Rgb([r, g, b]));
        }
    }
    image
}

#[cfg(test)]
mod test {

    use image::{
        GrayImage,
        ImageBuffer
    };

    #[test]
    fn test_assert_pixels_eq_passes() {
        let image: GrayImage = ImageBuffer::from_raw(3, 2, vec![
            00, 01, 02,
            10, 11, 12]).unwrap();

        assert_pixels_eq!(image, image);
    }

    #[test]
    #[should_panic]
    fn test_assert_pixels_eq_fails() {
        let image: GrayImage = ImageBuffer::from_raw(3, 2, vec![
            00, 01, 02,
            10, 11, 12]).unwrap();

        let diff: GrayImage = ImageBuffer::from_raw(3, 2, vec![
            00, 11, 02,
            10, 11, 12]).unwrap();

        assert_pixels_eq!(diff, image);
    }

    #[test]
    fn test_assert_pixels_eq_within_passes() {
        let image: GrayImage = ImageBuffer::from_raw(3, 2, vec![
            00, 01, 02,
            10, 11, 12]).unwrap();

        let diff: GrayImage = ImageBuffer::from_raw(3, 2, vec![
            00, 02, 02,
            10, 11, 12]).unwrap();

        assert_pixels_eq_within!(diff, image, 1);
    }

    #[test]
    #[should_panic]
    fn test_assert_pixels_eq_within_fails() {
        let image: GrayImage = ImageBuffer::from_raw(3, 2, vec![
            00, 01, 02,
            10, 11, 12]).unwrap();

        let diff: GrayImage = ImageBuffer::from_raw(3, 2, vec![
            00, 03, 02,
            10, 11, 12]).unwrap();

        assert_pixels_eq_within!(diff, image, 1);
    }
}
<commit_msg>Fix comment<commit_after>//! Utils for testing and debugging.

use image::{
    DynamicImage,
    GenericImage,
    GrayImage,
    Luma,
    open,
    Pixel,
    Rgb,
    RgbImage
};

use std::fmt::Debug;
use std::path::Path;

/// Panics if any pixels differ between the two input images.
#[macro_export]
macro_rules! assert_pixels_eq {
    ($actual:expr, $expected:expr) => ({
        assert_dimensions_match!($actual, $expected);
        let diffs = $crate::utils::pixel_diffs(&$actual, &$expected, |p, q| p != q);
        if !diffs.is_empty() {
            panic!($crate::utils::describe_pixel_diffs(diffs.into_iter()))
        }
     })
}

/// Panics if any pixels differ between the two images by more than the
/// given tolerance in a single channel.
#[macro_export]
macro_rules! assert_pixels_eq_within {
    ($actual:expr, $expected:expr, $channel_tolerance:expr) => ({

        assert_dimensions_match!($actual, $expected);
        let diffs = $crate::utils::pixel_diffs(&$actual, &$expected, |p, q| {

            use image::Pixel;
            let cp = p.2.channels();
            let cq = q.2.channels();
            if cp.len() != cq.len() {
                panic!("pixels have different channel counts. \
                    actual: {:?}, expected: {:?}", cp.len(), cq.len())
            }

            let mut large_diff = false;
            for i in 0..cp.len() {
                let sp = cp[i];
                let sq = cq[i];
                // Handle unsigned subpixels
                let diff = if sp > sq {sp - sq} else {sq - sp};
                if diff > $channel_tolerance {
                    large_diff = true;
                    break;
                }
            }

            large_diff
        });
        if !diffs.is_empty() {
            panic!($crate::utils::describe_pixel_diffs(diffs.into_iter()))
        }
    })
}

#[macro_export]
macro_rules! assert_dimensions_match {
    ($actual:expr, $expected:expr) => ({

        let actual_dim = $actual.dimensions();
        let expected_dim = $expected.dimensions();

        if actual_dim != expected_dim {
            panic!("dimensions do not match. \
                actual: {:?}, expected: {:?}", actual_dim, expected_dim)
        }
     })
}

/// Lists pixels that differ between left and right images.
pub fn pixel_diffs<I, F>(left: &I, right: &I, is_diff: F)
        -> Vec<((u32, u32, I::Pixel), (u32, u32, I::Pixel))>
    where I: GenericImage,
          I::Pixel: PartialEq,
          F: Fn((u32, u32, I::Pixel), (u32, u32, I::Pixel)) -> bool {

    // Can't just call $image.pixels(), as that needn't hit the
    // trait pixels method - ImageBuffer defines its own pixels
    // method with a different signature
    GenericImage::pixels(left)
        .zip(GenericImage::pixels(right))
        .filter(|&(p, q)| is_diff(p, q))//p != q)
        .collect::<Vec<_>>()
}

/// Gives a summary description of a list of pixel diffs for use in error messages.
pub fn describe_pixel_diffs<I, P>(diffs: I) -> String
    where I: Iterator<Item=(P, P)>,
          P: Debug {

    let mut err = "pixels do not match. ".to_string();
    err.push_str(&(diffs
        .take(5)
        .map(|d| format!("\nactual: {:?}, expected {:?} ", d.0, d.1))
        .collect::<Vec<_>>()
        .join("")));
    err
}

/// Loads image at given path, panicking on failure.
pub fn load_image_or_panic(path: &Path) -> DynamicImage {
     open(path)
         .ok()
         .expect(&format!("Could not load image at {:?}", path))
}

/// Gray image to use in benchmarks. This is neither noise nor
/// similar to natural images - it's just a convenience method
/// to produce an image that's not constant.
pub fn gray_bench_image(width: u32, height: u32) -> GrayImage {
    let mut image = GrayImage::new(width, height);
    for y in 0..image.height() {
        for x in 0..image.width() {
            let intensity = (x % 7 + y % 6) as u8;
            image.put_pixel(x, y, Luma([intensity]));
        }
    }
    image
}

/// RGB image to use in benchmarks. See comment on gray_bench_image.
pub fn rgb_bench_image(width: u32, height: u32) -> RgbImage {
    use std::cmp;
    let mut image = RgbImage::new(width, height);
    for y in 0..image.height() {
        for x in 0..image.width() {
            let r = (x % 7 + y % 6) as u8;
            let g = 255u8 - r;
            let b = cmp::min(r, g);
            image.put_pixel(x, y, Rgb([r, g, b]));
        }
    }
    image
}

#[cfg(test)]
mod test {

    use image::{
        GrayImage,
        ImageBuffer
    };

    #[test]
    fn test_assert_pixels_eq_passes() {
        let image: GrayImage = ImageBuffer::from_raw(3, 2, vec![
            00, 01, 02,
            10, 11, 12]).unwrap();

        assert_pixels_eq!(image, image);
    }

    #[test]
    #[should_panic]
    fn test_assert_pixels_eq_fails() {
        let image: GrayImage = ImageBuffer::from_raw(3, 2, vec![
            00, 01, 02,
            10, 11, 12]).unwrap();

        let diff: GrayImage = ImageBuffer::from_raw(3, 2, vec![
            00, 11, 02,
            10, 11, 12]).unwrap();

        assert_pixels_eq!(diff, image);
    }

    #[test]
    fn test_assert_pixels_eq_within_passes() {
        let image: GrayImage = ImageBuffer::from_raw(3, 2, vec![
            00, 01, 02,
            10, 11, 12]).unwrap();

        let diff: GrayImage = ImageBuffer::from_raw(3, 2, vec![
            00, 02, 02,
            10, 11, 12]).unwrap();

        assert_pixels_eq_within!(diff, image, 1);
    }

    #[test]
    #[should_panic]
    fn test_assert_pixels_eq_within_fails() {
        let image: GrayImage = ImageBuffer::from_raw(3, 2, vec![
            00, 01, 02,
            10, 11, 12]).unwrap();

        let diff: GrayImage = ImageBuffer::from_raw(3, 2, vec![
            00, 03, 02,
            10, 11, 12]).unwrap();

        assert_pixels_eq_within!(diff, image, 1);
    }
}
<|endoftext|>


<commit_before>use std::rc::Rc;
use consumer::*;
use producer::*;
use stream::*;

pub struct Value<T> {
    value: T,
}

impl<T> Value<T> {
    /// Constructs a new `Stream` based on a `Value<T>`.
    ///
    /// # Examples
    ///
    /// ```
    /// use asyncplify::*;
    ///
    /// Value::new(5)
    ///     .tap(|v| println!("{}", v))
    ///     .subscribe();
    /// ```
    pub fn new(value: T) -> Self {
        Value { value: value }
    }
}

impl<T> Stream<T> for Value<T>
    where T: Clone
{
    fn consume<C: Consumer<T>>(self, mut consumer: C) {
        let producer = Rc::new(Producer::new());

        consumer.init(producer.clone());

        if !producer.is_closed() {
            consumer.emit(self.value.clone());
        }

        if !producer.is_closed() {
            consumer.end();
        }
    }
}<commit_msg>Add support for mapRef and mapRefMut<commit_after>use std::rc::Rc;
use consumer::*;
use producer::*;
use stream::*;

pub struct Value<T> {
    value: T,
}

pub struct ValueRef<'a, T: 'a> {
    value: &'a T,
}

pub struct ValueRefMut<'a, T: 'a> {
    value: &'a mut T,
}

impl<T> Value<T> {
    /// Constructs a new `Stream` based on a `Value<T>`.
    ///
    /// # Examples
    ///
    /// ```
    /// use asyncplify::*;
    ///
    /// Value::new(5)
    ///     .tap(|v| println!("{}", v))
    ///     .subscribe();
    /// ```
    pub fn new(value: T) -> Self {
        Value { value: value }
    }
}

impl<'a, T> ValueRef<'a, T> {
    pub fn new(value: &'a T) -> Self {
        ValueRef { value: value }
    }
}

impl<'a, T> ValueRefMut<'a, T> {
    pub fn new(value: &'a mut T) -> Self {
        ValueRefMut { value: value }
    }
}

impl<T> Stream<T> for Value<T> {
    fn consume<C: Consumer<T>>(self, mut consumer: C) {
        let producer = Rc::new(Producer::new());

        consumer.init(producer.clone());

        if !producer.is_closed() {
            consumer.emit(self.value);
        }

        if !producer.is_closed() {
            consumer.end();
        }
    }
}

impl<'a, T> StreamRef<T> for ValueRef<'a, T> {
    fn consume<C: ConsumerRef<T>>(self, mut consumer: C) {
        let producer = Rc::new(Producer::new());

        consumer.init(producer.clone());

        if !producer.is_closed() {
            consumer.emit(self.value);
        }

        if !producer.is_closed() {
            consumer.end();
        }
    }
}

impl<'a, T> StreamRefMut<T> for ValueRefMut<'a, T> {
    fn consume<C: ConsumerRefMut<T>>(self, mut consumer: C) {
        let producer = Rc::new(Producer::new());

        consumer.init(producer.clone());

        if !producer.is_closed() {
            consumer.emit(self.value);
        }

        if !producer.is_closed() {
            consumer.end();
        }
    }
}<|endoftext|>


<commit_before>// Copyright 2015 Nicholas Bishop
//
// Orientation code adapted from "Real-Time Collision Detection" by
// Christer Ericson, published by Morgan Kaufmann Publishers,
// Copyright 2005 Elsevier Inc
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::ops::{Add, Div, Mul, Sub};
use util::CastF32;
use vec3f::Vec3f;

/// Vector with two f32 components
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Vec2f {
    pub x: f32,
    pub y: f32
}

impl Vec2f {
    /// Create a Vec2f from two components
    pub fn new(x: f32, y: f32) -> Vec2f {
        Vec2f { x: x,
                y: y }
    }

    pub fn cross(self, other: Vec2f) -> f32 {
        self.x * other.y - self.y * other.x
    }

    pub fn lerp(self, other: Vec2f, t: f32) -> Vec2f {
        self * (1.0 - t) + other * t
    }

    pub fn dot(self, other: Vec2f) -> f32 {
        self.x * other.x + self.y * other.y
    }

    pub fn vec3f(self) -> Vec3f {
        Vec3f::new(self.x, self.y, 0.0)
    }

    pub fn distance_squared(self, other: Vec2f) -> f32 {
        (self - other).magnitude_squared()
    }

    pub fn distance(self, other: Vec2f) -> f32 {
        self.distance_squared(other).sqrt()
    }

    pub fn magnitude_squared(self) -> f32 {
        self.dot(self)
    }

    pub fn magnitude(self) -> f32 {
        self.magnitude_squared().sqrt()
    }

    pub fn normalized(self) -> Option<Vec2f> {
        let m = self.magnitude();
        if m == 0.0 {
            None
        }
        else {
            Some(Vec2f::new(self.x / m, self.y / m))
        }
    }
}

impl Add for Vec2f {
    type Output = Vec2f;
    fn add(self, v: Vec2f) -> Vec2f {
        Vec2f::new(self.x + v.x, self.y + v.y)
    }
}

impl Sub for Vec2f {
    type Output = Vec2f;
    fn sub(self, v: Vec2f) -> Vec2f {
        Vec2f::new(self.x - v.x, self.y - v.y)
    }
}

impl Mul<f32> for Vec2f {
    type Output = Vec2f;
    fn mul(self, s: f32) -> Vec2f {
        Vec2f::new(self.x * s, self.y * s)
    }
}

impl Div<f32> for Vec2f {
    type Output = Vec2f;
    fn div(self, s: f32) -> Vec2f {
        Vec2f::new(self.x / s, self.y / s)
    }
}

pub fn detf_2x2(top_left: f32, top_right: f32,
                bot_left: f32, bot_right: f32) -> f32 {
    top_left * bot_right - top_right * bot_left
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Line2f {
    pub points: (Vec2f, Vec2f)
}

impl Line2f {
    pub fn new(a: Vec2f, b: Vec2f) -> Line2f {
        Line2f { points: (a, b) }
    }

    pub fn closest_parametric_point(self, point: Vec2f) -> f32 {
        let p0p = point - self.points.0;
        let p0p1 = self.points.1 - self.points.0;

        p0p.dot(p0p1) / p0p1.dot(p0p1)
    }

    pub fn point_distance_squared(self, point: Vec2f) -> f32 {
        // TODO(nicholasbishop): may be a more way to calculate this
        let para = self.closest_parametric_point(point);
        let cart = self.cart_from_para(para);
        cart.distance_squared(point)
    }

    pub fn cart_from_para(self, t: f32) -> Vec2f {
        self.points.0.lerp(self.points.1, t)
    }

    /// If result is greater than zero `point` lies to the left of the
    /// line. If result is less than zero `point` lies to the
    /// right. If result is zero, the point is on the line.
    ///
    /// The value is also twice the signed area of the triangle
    /// `(points.0, points.1, point)` (positive if counterclockwise,
    /// otherwise negative).
    ///
    /// Adapted from "Real-Time Collision Detection" by Christer
    /// Ericson, published by Morgan Kaufmann Publishers, Copyright
    /// 2005 Elsevier Inc
    pub fn orient(self, point: Vec2f) -> f32 {
        detf_2x2(self.points.0.x - point.x, self.points.0.y - point.y,
                 self.points.1.x - point.x, self.points.1.y - point.y)
    }
}

/// Create a Vec2f from x and y inputs
///
/// This is a convenience function that provides a little more
/// flexibility than Vec2f::new in that it will happily take numbers
/// that aren't f32 (including a mix of different types for each
/// component). Vec2f is such a common type that it seems reasonable
/// to provide a little extra ease of use.
pub fn vec2f<X: CastF32, Y: CastF32>(x: X, y: Y) -> Vec2f {
    Vec2f { x: x.as_f32(), y: y.as_f32() }
}
<commit_msg>Add Line2f::reverse<commit_after>// Copyright 2015 Nicholas Bishop
//
// Orientation code adapted from "Real-Time Collision Detection" by
// Christer Ericson, published by Morgan Kaufmann Publishers,
// Copyright 2005 Elsevier Inc
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::ops::{Add, Div, Mul, Sub};
use util::CastF32;
use vec3f::Vec3f;

/// Vector with two f32 components
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Vec2f {
    pub x: f32,
    pub y: f32
}

impl Vec2f {
    /// Create a Vec2f from two components
    pub fn new(x: f32, y: f32) -> Vec2f {
        Vec2f { x: x,
                y: y }
    }

    pub fn cross(self, other: Vec2f) -> f32 {
        self.x * other.y - self.y * other.x
    }

    pub fn lerp(self, other: Vec2f, t: f32) -> Vec2f {
        self * (1.0 - t) + other * t
    }

    pub fn dot(self, other: Vec2f) -> f32 {
        self.x * other.x + self.y * other.y
    }

    pub fn vec3f(self) -> Vec3f {
        Vec3f::new(self.x, self.y, 0.0)
    }

    pub fn distance_squared(self, other: Vec2f) -> f32 {
        (self - other).magnitude_squared()
    }

    pub fn distance(self, other: Vec2f) -> f32 {
        self.distance_squared(other).sqrt()
    }

    pub fn magnitude_squared(self) -> f32 {
        self.dot(self)
    }

    pub fn magnitude(self) -> f32 {
        self.magnitude_squared().sqrt()
    }

    pub fn normalized(self) -> Option<Vec2f> {
        let m = self.magnitude();
        if m == 0.0 {
            None
        }
        else {
            Some(Vec2f::new(self.x / m, self.y / m))
        }
    }
}

impl Add for Vec2f {
    type Output = Vec2f;
    fn add(self, v: Vec2f) -> Vec2f {
        Vec2f::new(self.x + v.x, self.y + v.y)
    }
}

impl Sub for Vec2f {
    type Output = Vec2f;
    fn sub(self, v: Vec2f) -> Vec2f {
        Vec2f::new(self.x - v.x, self.y - v.y)
    }
}

impl Mul<f32> for Vec2f {
    type Output = Vec2f;
    fn mul(self, s: f32) -> Vec2f {
        Vec2f::new(self.x * s, self.y * s)
    }
}

impl Div<f32> for Vec2f {
    type Output = Vec2f;
    fn div(self, s: f32) -> Vec2f {
        Vec2f::new(self.x / s, self.y / s)
    }
}

pub fn detf_2x2(top_left: f32, top_right: f32,
                bot_left: f32, bot_right: f32) -> f32 {
    top_left * bot_right - top_right * bot_left
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Line2f {
    pub points: (Vec2f, Vec2f)
}

impl Line2f {
    pub fn new(a: Vec2f, b: Vec2f) -> Line2f {
        Line2f { points: (a, b) }
    }

    pub fn reverse(self) -> Line2f {
        Line2f::new(self.points.1, self.points.0)
    }

    pub fn closest_parametric_point(self, point: Vec2f) -> f32 {
        let p0p = point - self.points.0;
        let p0p1 = self.points.1 - self.points.0;

        p0p.dot(p0p1) / p0p1.dot(p0p1)
    }

    pub fn point_distance_squared(self, point: Vec2f) -> f32 {
        // TODO(nicholasbishop): may be a more way to calculate this
        let para = self.closest_parametric_point(point);
        let cart = self.cart_from_para(para);
        cart.distance_squared(point)
    }

    pub fn cart_from_para(self, t: f32) -> Vec2f {
        self.points.0.lerp(self.points.1, t)
    }

    /// If result is greater than zero `point` lies to the left of the
    /// line. If result is less than zero `point` lies to the
    /// right. If result is zero, the point is on the line.
    ///
    /// The value is also twice the signed area of the triangle
    /// `(points.0, points.1, point)` (positive if counterclockwise,
    /// otherwise negative).
    ///
    /// Adapted from "Real-Time Collision Detection" by Christer
    /// Ericson, published by Morgan Kaufmann Publishers, Copyright
    /// 2005 Elsevier Inc
    pub fn orient(self, point: Vec2f) -> f32 {
        detf_2x2(self.points.0.x - point.x, self.points.0.y - point.y,
                 self.points.1.x - point.x, self.points.1.y - point.y)
    }
}

/// Create a Vec2f from x and y inputs
///
/// This is a convenience function that provides a little more
/// flexibility than Vec2f::new in that it will happily take numbers
/// that aren't f32 (including a mix of different types for each
/// component). Vec2f is such a common type that it seems reasonable
/// to provide a little extra ease of use.
pub fn vec2f<X: CastF32, Y: CastF32>(x: X, y: Y) -> Vec2f {
    Vec2f { x: x.as_f32(), y: y.as_f32() }
}
<|endoftext|>


<commit_before>//! Types for the [`m.room.power_levels`] event.
//!
//! [`m.room.power_levels`]: https://spec.matrix.org/v1.2/client-server-api/#mroompower_levels

use std::collections::BTreeMap;

use js_int::{int, Int};
use ruma_macros::EventContent;
use serde::{Deserialize, Serialize};

use crate::{
    events::RoomEventType,
    power_levels::{default_power_level, NotificationPowerLevels},
    UserId,
};

/// The content of an `m.room.power_levels` event.
///
/// Defines the power levels (privileges) of users in the room.
#[derive(Clone, Debug, Deserialize, Serialize, EventContent)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[ruma_event(type = "m.room.power_levels", kind = State)]
pub struct RoomPowerLevelsEventContent {
    /// The level required to ban a user.
    ///
    /// If you activate the `compat` feature, deserialization will work for stringified
    /// integers too.
    #[cfg_attr(
        feature = "compat",
        serde(deserialize_with = "crate::serde::deserialize_v1_powerlevel")
    )]
    #[serde(default = "default_power_level", skip_serializing_if = "is_default_power_level")]
    #[ruma_event(skip_redaction)]
    pub ban: Int,

    /// The level required to send specific event types.
    ///
    /// This is a mapping from event type to power level required.
    ///
    /// If you activate the `compat` feature, deserialization will work for stringified
    /// integers too.
    #[cfg_attr(
        feature = "compat",
        serde(deserialize_with = "crate::serde::btreemap_deserialize_v1_powerlevel_values")
    )]
    #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
    #[ruma_event(skip_redaction)]
    pub events: BTreeMap<RoomEventType, Int>,

    /// The default level required to send message events.
    ///
    /// If you activate the `compat` feature, deserialization will work for stringified
    /// integers too.
    #[cfg_attr(
        feature = "compat",
        serde(deserialize_with = "crate::serde::deserialize_v1_powerlevel")
    )]
    #[serde(default, skip_serializing_if = "crate::serde::is_default")]
    #[ruma_event(skip_redaction)]
    pub events_default: Int,

    /// The level required to invite a user.
    ///
    /// If you activate the `compat` feature, deserialization will work for stringified
    /// integers too.
    #[cfg_attr(
        feature = "compat",
        serde(deserialize_with = "crate::serde::deserialize_v1_powerlevel")
    )]
    #[serde(default, skip_serializing_if = "crate::serde::is_default")]
    pub invite: Int,

    /// The level required to kick a user.
    ///
    /// If you activate the `compat` feature, deserialization will work for stringified
    /// integers too.
    #[cfg_attr(
        feature = "compat",
        serde(deserialize_with = "crate::serde::deserialize_v1_powerlevel")
    )]
    #[serde(default = "default_power_level", skip_serializing_if = "is_default_power_level")]
    #[ruma_event(skip_redaction)]
    pub kick: Int,

    /// The level required to redact an event.
    ///
    /// If you activate the `compat` feature, deserialization will work for stringified
    /// integers too.
    #[cfg_attr(
        feature = "compat",
        serde(deserialize_with = "crate::serde::deserialize_v1_powerlevel")
    )]
    #[serde(default = "default_power_level", skip_serializing_if = "is_default_power_level")]
    #[ruma_event(skip_redaction)]
    pub redact: Int,

    /// The default level required to send state events.
    ///
    /// If you activate the `compat` feature, deserialization will work for stringified
    /// integers too.
    #[cfg_attr(
        feature = "compat",
        serde(deserialize_with = "crate::serde::deserialize_v1_powerlevel")
    )]
    #[serde(default = "default_power_level", skip_serializing_if = "is_default_power_level")]
    #[ruma_event(skip_redaction)]
    pub state_default: Int,

    /// The power levels for specific users.
    ///
    /// This is a mapping from `user_id` to power level for that user.
    ///
    /// If you activate the `compat` feature, deserialization will work for stringified
    /// integers too.
    #[cfg_attr(
        feature = "compat",
        serde(deserialize_with = "crate::serde::btreemap_deserialize_v1_powerlevel_values")
    )]
    #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
    #[ruma_event(skip_redaction)]
    pub users: BTreeMap<Box<UserId>, Int>,

    /// The default power level for every user in the room.
    ///
    /// If you activate the `compat` feature, deserialization will work for stringified
    /// integers too.
    #[cfg_attr(
        feature = "compat",
        serde(deserialize_with = "crate::serde::deserialize_v1_powerlevel")
    )]
    #[serde(default, skip_serializing_if = "crate::serde::is_default")]
    #[ruma_event(skip_redaction)]
    pub users_default: Int,

    /// The power level requirements for specific notification types.
    ///
    /// This is a mapping from `key` to power level for that notifications key.
    #[serde(default, skip_serializing_if = "crate::serde::is_default")]
    pub notifications: NotificationPowerLevels,
}

impl RoomPowerLevelsEventContent {
    /// Creates a new `RoomPowerLevelsEventContent` with all-default values.
    pub fn new() -> Self {
        // events_default and users_default having a default of 0 while the others have a default
        // of 50 is not an oversight, these defaults are from the Matrix specification.
        Self {
            ban: default_power_level(),
            events: BTreeMap::new(),
            events_default: int!(0),
            invite: int!(0),
            kick: default_power_level(),
            redact: default_power_level(),
            state_default: default_power_level(),
            users: BTreeMap::new(),
            users_default: int!(0),
            notifications: NotificationPowerLevels::default(),
        }
    }
}

impl Default for RoomPowerLevelsEventContent {
    fn default() -> Self {
        Self::new()
    }
}

/// Used with `#[serde(skip_serializing_if)]` to omit default power levels.
#[allow(clippy::trivially_copy_pass_by_ref)]
fn is_default_power_level(l: &Int) -> bool {
    *l == int!(50)
}

#[cfg(test)]
mod tests {
    use std::collections::BTreeMap;

    use crate::{event_id, room_id, user_id, MilliSecondsSinceUnixEpoch};
    use assign::assign;
    use js_int::{int, uint};
    use maplit::btreemap;
    use serde_json::{json, to_value as to_json_value};

    use super::{default_power_level, NotificationPowerLevels, RoomPowerLevelsEventContent};
    use crate::events::{OriginalStateEvent, StateUnsigned};

    #[test]
    fn serialization_with_optional_fields_as_none() {
        let default = default_power_level();

        let power_levels_event = OriginalStateEvent {
            content: RoomPowerLevelsEventContent {
                ban: default,
                events: BTreeMap::new(),
                events_default: int!(0),
                invite: int!(0),
                kick: default,
                redact: default,
                state_default: default,
                users: BTreeMap::new(),
                users_default: int!(0),
                notifications: NotificationPowerLevels::default(),
            },
            event_id: event_id!("$h29iv0s8:example.com").to_owned(),
            origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(1)),
            room_id: room_id!("!n8f893n9:example.com").to_owned(),
            unsigned: StateUnsigned::default(),
            sender: user_id!("@carl:example.com").to_owned(),
            state_key: "".into(),
        };

        let actual = to_json_value(&power_levels_event).unwrap();
        let expected = json!({
            "content": {},
            "event_id": "$h29iv0s8:example.com",
            "origin_server_ts": 1,
            "room_id": "!n8f893n9:example.com",
            "sender": "@carl:example.com",
            "state_key": "",
            "type": "m.room.power_levels"
        });

        assert_eq!(actual, expected);
    }

    #[test]
    fn serialization_with_all_fields() {
        let user = user_id!("@carl:example.com");
        let power_levels_event = OriginalStateEvent {
            content: RoomPowerLevelsEventContent {
                ban: int!(23),
                events: btreemap! {
                    "m.dummy".into() => int!(23)
                },
                events_default: int!(23),
                invite: int!(23),
                kick: int!(23),
                redact: int!(23),
                state_default: int!(23),
                users: btreemap! {
                    user.to_owned() => int!(23)
                },
                users_default: int!(23),
                notifications: assign!(NotificationPowerLevels::new(), { room: int!(23) }),
            },
            event_id: event_id!("$h29iv0s8:example.com").to_owned(),
            origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(1)),
            room_id: room_id!("!n8f893n9:example.com").to_owned(),
            unsigned: StateUnsigned {
                age: Some(int!(100)),
                prev_content: Some(RoomPowerLevelsEventContent {
                    // Make just one field different so we at least know they're two different
                    // objects.
                    ban: int!(42),
                    events: btreemap! {
                        "m.dummy".into() => int!(42)
                    },
                    events_default: int!(42),
                    invite: int!(42),
                    kick: int!(42),
                    redact: int!(42),
                    state_default: int!(42),
                    users: btreemap! {
                        user.to_owned() => int!(42)
                    },
                    users_default: int!(42),
                    notifications: assign!(NotificationPowerLevels::new(), { room: int!(42) }),
                }),
                ..StateUnsigned::default()
            },
            sender: user.to_owned(),
            state_key: "".into(),
        };

        let actual = to_json_value(&power_levels_event).unwrap();
        let expected = json!({
            "content": {
                "ban": 23,
                "events": {
                    "m.dummy": 23
                },
                "events_default": 23,
                "invite": 23,
                "kick": 23,
                "redact": 23,
                "state_default": 23,
                "users": {
                    "@carl:example.com": 23
                },
                "users_default": 23,
                "notifications": {
                    "room": 23
                }
            },
            "event_id": "$h29iv0s8:example.com",
            "origin_server_ts": 1,
            "room_id": "!n8f893n9:example.com",
            "sender": "@carl:example.com",
            "state_key": "",
            "type": "m.room.power_levels",
            "unsigned": {
                "age": 100,
                "prev_content": {
                    "ban": 42,
                    "events": {
                        "m.dummy": 42
                    },
                    "events_default": 42,
                    "invite": 42,
                    "kick": 42,
                    "redact": 42,
                    "state_default": 42,
                    "users": {
                        "@carl:example.com": 42
                    },
                    "users_default": 42,
                    "notifications": {
                        "room": 42
                    },
                },
            }
        });

        assert_eq!(actual, expected);
    }
}
<commit_msg>events: Fix comment<commit_after>//! Types for the [`m.room.power_levels`] event.
//!
//! [`m.room.power_levels`]: https://spec.matrix.org/v1.2/client-server-api/#mroompower_levels

use std::collections::BTreeMap;

use js_int::{int, Int};
use ruma_macros::EventContent;
use serde::{Deserialize, Serialize};

use crate::{
    events::RoomEventType,
    power_levels::{default_power_level, NotificationPowerLevels},
    UserId,
};

/// The content of an `m.room.power_levels` event.
///
/// Defines the power levels (privileges) of users in the room.
#[derive(Clone, Debug, Deserialize, Serialize, EventContent)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[ruma_event(type = "m.room.power_levels", kind = State)]
pub struct RoomPowerLevelsEventContent {
    /// The level required to ban a user.
    ///
    /// If you activate the `compat` feature, deserialization will work for stringified
    /// integers too.
    #[cfg_attr(
        feature = "compat",
        serde(deserialize_with = "crate::serde::deserialize_v1_powerlevel")
    )]
    #[serde(default = "default_power_level", skip_serializing_if = "is_default_power_level")]
    #[ruma_event(skip_redaction)]
    pub ban: Int,

    /// The level required to send specific event types.
    ///
    /// This is a mapping from event type to power level required.
    ///
    /// If you activate the `compat` feature, deserialization will work for stringified
    /// integers too.
    #[cfg_attr(
        feature = "compat",
        serde(deserialize_with = "crate::serde::btreemap_deserialize_v1_powerlevel_values")
    )]
    #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
    #[ruma_event(skip_redaction)]
    pub events: BTreeMap<RoomEventType, Int>,

    /// The default level required to send message events.
    ///
    /// If you activate the `compat` feature, deserialization will work for stringified
    /// integers too.
    #[cfg_attr(
        feature = "compat",
        serde(deserialize_with = "crate::serde::deserialize_v1_powerlevel")
    )]
    #[serde(default, skip_serializing_if = "crate::serde::is_default")]
    #[ruma_event(skip_redaction)]
    pub events_default: Int,

    /// The level required to invite a user.
    ///
    /// If you activate the `compat` feature, deserialization will work for stringified
    /// integers too.
    #[cfg_attr(
        feature = "compat",
        serde(deserialize_with = "crate::serde::deserialize_v1_powerlevel")
    )]
    #[serde(default, skip_serializing_if = "crate::serde::is_default")]
    pub invite: Int,

    /// The level required to kick a user.
    ///
    /// If you activate the `compat` feature, deserialization will work for stringified
    /// integers too.
    #[cfg_attr(
        feature = "compat",
        serde(deserialize_with = "crate::serde::deserialize_v1_powerlevel")
    )]
    #[serde(default = "default_power_level", skip_serializing_if = "is_default_power_level")]
    #[ruma_event(skip_redaction)]
    pub kick: Int,

    /// The level required to redact an event.
    ///
    /// If you activate the `compat` feature, deserialization will work for stringified
    /// integers too.
    #[cfg_attr(
        feature = "compat",
        serde(deserialize_with = "crate::serde::deserialize_v1_powerlevel")
    )]
    #[serde(default = "default_power_level", skip_serializing_if = "is_default_power_level")]
    #[ruma_event(skip_redaction)]
    pub redact: Int,

    /// The default level required to send state events.
    ///
    /// If you activate the `compat` feature, deserialization will work for stringified
    /// integers too.
    #[cfg_attr(
        feature = "compat",
        serde(deserialize_with = "crate::serde::deserialize_v1_powerlevel")
    )]
    #[serde(default = "default_power_level", skip_serializing_if = "is_default_power_level")]
    #[ruma_event(skip_redaction)]
    pub state_default: Int,

    /// The power levels for specific users.
    ///
    /// This is a mapping from `user_id` to power level for that user.
    ///
    /// If you activate the `compat` feature, deserialization will work for stringified
    /// integers too.
    #[cfg_attr(
        feature = "compat",
        serde(deserialize_with = "crate::serde::btreemap_deserialize_v1_powerlevel_values")
    )]
    #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
    #[ruma_event(skip_redaction)]
    pub users: BTreeMap<Box<UserId>, Int>,

    /// The default power level for every user in the room.
    ///
    /// If you activate the `compat` feature, deserialization will work for stringified
    /// integers too.
    #[cfg_attr(
        feature = "compat",
        serde(deserialize_with = "crate::serde::deserialize_v1_powerlevel")
    )]
    #[serde(default, skip_serializing_if = "crate::serde::is_default")]
    #[ruma_event(skip_redaction)]
    pub users_default: Int,

    /// The power level requirements for specific notification types.
    ///
    /// This is a mapping from `key` to power level for that notifications key.
    #[serde(default, skip_serializing_if = "crate::serde::is_default")]
    pub notifications: NotificationPowerLevels,
}

impl RoomPowerLevelsEventContent {
    /// Creates a new `RoomPowerLevelsEventContent` with all-default values.
    pub fn new() -> Self {
        // events_default, users_default and invite having a default of 0 while the others have a
        // default of 50 is not an oversight, these defaults are from the Matrix specification.
        Self {
            ban: default_power_level(),
            events: BTreeMap::new(),
            events_default: int!(0),
            invite: int!(0),
            kick: default_power_level(),
            redact: default_power_level(),
            state_default: default_power_level(),
            users: BTreeMap::new(),
            users_default: int!(0),
            notifications: NotificationPowerLevels::default(),
        }
    }
}

impl Default for RoomPowerLevelsEventContent {
    fn default() -> Self {
        Self::new()
    }
}

/// Used with `#[serde(skip_serializing_if)]` to omit default power levels.
#[allow(clippy::trivially_copy_pass_by_ref)]
fn is_default_power_level(l: &Int) -> bool {
    *l == int!(50)
}

#[cfg(test)]
mod tests {
    use std::collections::BTreeMap;

    use crate::{event_id, room_id, user_id, MilliSecondsSinceUnixEpoch};
    use assign::assign;
    use js_int::{int, uint};
    use maplit::btreemap;
    use serde_json::{json, to_value as to_json_value};

    use super::{default_power_level, NotificationPowerLevels, RoomPowerLevelsEventContent};
    use crate::events::{OriginalStateEvent, StateUnsigned};

    #[test]
    fn serialization_with_optional_fields_as_none() {
        let default = default_power_level();

        let power_levels_event = OriginalStateEvent {
            content: RoomPowerLevelsEventContent {
                ban: default,
                events: BTreeMap::new(),
                events_default: int!(0),
                invite: int!(0),
                kick: default,
                redact: default,
                state_default: default,
                users: BTreeMap::new(),
                users_default: int!(0),
                notifications: NotificationPowerLevels::default(),
            },
            event_id: event_id!("$h29iv0s8:example.com").to_owned(),
            origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(1)),
            room_id: room_id!("!n8f893n9:example.com").to_owned(),
            unsigned: StateUnsigned::default(),
            sender: user_id!("@carl:example.com").to_owned(),
            state_key: "".into(),
        };

        let actual = to_json_value(&power_levels_event).unwrap();
        let expected = json!({
            "content": {},
            "event_id": "$h29iv0s8:example.com",
            "origin_server_ts": 1,
            "room_id": "!n8f893n9:example.com",
            "sender": "@carl:example.com",
            "state_key": "",
            "type": "m.room.power_levels"
        });

        assert_eq!(actual, expected);
    }

    #[test]
    fn serialization_with_all_fields() {
        let user = user_id!("@carl:example.com");
        let power_levels_event = OriginalStateEvent {
            content: RoomPowerLevelsEventContent {
                ban: int!(23),
                events: btreemap! {
                    "m.dummy".into() => int!(23)
                },
                events_default: int!(23),
                invite: int!(23),
                kick: int!(23),
                redact: int!(23),
                state_default: int!(23),
                users: btreemap! {
                    user.to_owned() => int!(23)
                },
                users_default: int!(23),
                notifications: assign!(NotificationPowerLevels::new(), { room: int!(23) }),
            },
            event_id: event_id!("$h29iv0s8:example.com").to_owned(),
            origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(1)),
            room_id: room_id!("!n8f893n9:example.com").to_owned(),
            unsigned: StateUnsigned {
                age: Some(int!(100)),
                prev_content: Some(RoomPowerLevelsEventContent {
                    // Make just one field different so we at least know they're two different
                    // objects.
                    ban: int!(42),
                    events: btreemap! {
                        "m.dummy".into() => int!(42)
                    },
                    events_default: int!(42),
                    invite: int!(42),
                    kick: int!(42),
                    redact: int!(42),
                    state_default: int!(42),
                    users: btreemap! {
                        user.to_owned() => int!(42)
                    },
                    users_default: int!(42),
                    notifications: assign!(NotificationPowerLevels::new(), { room: int!(42) }),
                }),
                ..StateUnsigned::default()
            },
            sender: user.to_owned(),
            state_key: "".into(),
        };

        let actual = to_json_value(&power_levels_event).unwrap();
        let expected = json!({
            "content": {
                "ban": 23,
                "events": {
                    "m.dummy": 23
                },
                "events_default": 23,
                "invite": 23,
                "kick": 23,
                "redact": 23,
                "state_default": 23,
                "users": {
                    "@carl:example.com": 23
                },
                "users_default": 23,
                "notifications": {
                    "room": 23
                }
            },
            "event_id": "$h29iv0s8:example.com",
            "origin_server_ts": 1,
            "room_id": "!n8f893n9:example.com",
            "sender": "@carl:example.com",
            "state_key": "",
            "type": "m.room.power_levels",
            "unsigned": {
                "age": 100,
                "prev_content": {
                    "ban": 42,
                    "events": {
                        "m.dummy": 42
                    },
                    "events_default": 42,
                    "invite": 42,
                    "kick": 42,
                    "redact": 42,
                    "state_default": 42,
                    "users": {
                        "@carl:example.com": 42
                    },
                    "users_default": 42,
                    "notifications": {
                        "room": 42
                    },
                },
            }
        });

        assert_eq!(actual, expected);
    }
}
<|endoftext|>


<commit_before>// Basic types
pub type Color = usize; // 0 or 1
pub type File = usize;  // from 0 to 7
pub type Rank = usize;  // from 0 to 7
pub type Square = usize;  // from 0 to 63
pub type PieceType = usize;  // from 0 to 5
pub type CastlingRights = [(bool, bool); 2];  // (King-side, Queen-side)

// Color
pub const WHITE: Color = 0;
pub const BLACK: Color = 1;

// Piece types
pub const QUEEN: PieceType = 0;
pub const ROOK: PieceType = 1;
pub const BISHOP: PieceType = 2;
pub const KNIGHT: PieceType = 3;
pub const KING: PieceType = 4;
pub const PAWN: PieceType = 5;

// Move
pub enum MoveType {
    Normal,
    EnPassant,
    Promotion,
    Castling,
}

pub struct Move(u16);

impl Move {
    pub fn new(move_type: MoveType, orig: Square, dest: Square, pp_type: PieceType) -> Move {
        assert!(orig <= 63);
        assert!(dest <= 63);
        assert!(pp_type <= 3);
        let m_type = match move_type {
            MoveType::Normal => 0,
            MoveType::EnPassant => 1,
            MoveType::Promotion => 2,
            MoveType::Castling => 3,
        };
        Move(m_type << 14 | (pp_type << 12) as u16 | (orig << 6) as u16 | (dest as u16))
    }

    pub fn move_type(&self) -> MoveType {
        match (self.0 & (0b11 << 14)) >> 14 {
            0 => MoveType::Normal,
            1 => MoveType::EnPassant,
            2 => MoveType::Promotion,
            3 => MoveType::Castling,
            _ => panic!("Impossible move type"),
        }
    }

    pub fn orig_square(&self) -> Square {
        (self.0 & (0b111111 << 6) >> 6) as Square
    }

    pub fn dest_square(&self) -> Square {
        (self.0 & 0b111111) as Square
    }

    pub fn promotion_piece_type(&self) -> PieceType {
        (self.0 & (0b11 << 12) >> 12) as PieceType
    }

}

pub fn square(file: File, rank: Rank) -> Square {
    assert!(file < 8);
    assert!(rank < 8);
    rank * 8 + file
}
<commit_msg>Improve Move type.<commit_after>// Basic types
pub type Color = usize; // 0 or 1
pub type File = usize;  // from 0 to 7
pub type Rank = usize;  // from 0 to 7
pub type Square = usize;  // from 0 to 63
pub type PieceType = usize;  // from 0 to 5
pub type MoveType = usize;  // from 0 to 3
pub type CastlingRights = [(bool, bool); 2];  // (King-side, Queen-side)

// Color
pub const WHITE: Color = 0;
pub const BLACK: Color = 1;

// Piece types
pub const QUEEN: PieceType = 0;
pub const ROOK: PieceType = 1;
pub const BISHOP: PieceType = 2;
pub const KNIGHT: PieceType = 3;
pub const KING: PieceType = 4;
pub const PAWN: PieceType = 5;

// Move types
pub const MOVE_NORMAL: MoveType = 0;
pub const MOVE_ENPASSANT: MoveType = 1;
pub const MOVE_PROMOTION: MoveType = 2;
pub const MOVE_CASTLING: MoveType = 3;

pub struct Move(u16);

impl Move {
    #[inline]
    pub fn new(m_type: MoveType, orig: Square, dest: Square, pp_type: PieceType) -> Move {
        assert!(m_type <= 3);
        assert!(orig <= 63);
        assert!(dest <= 63);
        assert!(pp_type <= 3);
        Move( ((m_type << 14) | (pp_type << 12) | (orig << 6) | dest) as u16 )
    }

    #[inline]
    pub fn move_type(&self) -> MoveType {
        ((self.0 & (0b11 << 14)) >> 14) as MoveType
    }

    #[inline]
    pub fn orig_square(&self) -> Square {
        (self.0 & (0b111111 << 6) >> 6) as Square
    }

    #[inline]
    pub fn dest_square(&self) -> Square {
        (self.0 & 0b111111) as Square
    }

    #[inline]
    pub fn promotion_piece_type(&self) -> PieceType {
        (self.0 & (0b11 << 12) >> 12) as PieceType
    }
}

#[inline]
pub fn square(file: File, rank: Rank) -> Square {
    assert!(file < 8);
    assert!(rank < 8);
    rank * 8 + file
}
<|endoftext|>