<commit_before>use rustc_serialize::json::Json;
use rustc_serialize::json;
use matrix::json as mjson;
use std::fmt;

#[derive(Clone, Debug, PartialEq)]
pub struct EventID {
    pub id: String,
    pub homeserver: String
}

impl EventID {
    pub fn from_str(s: &str) -> Self {
        let parts: Vec<&str> = s.split(":").collect();
        EventID {
            id: parts[0][1..].to_string(),
            homeserver: parts[1].to_string()
        }
    }
}

#[derive(Clone, Debug)]
pub struct UserID {
    pub nickname: String,
    pub homeserver: String
}

impl UserID {
    pub fn from_str(s: &str) -> Self {
        let parts: Vec<&str> = s.split(":").collect();
        UserID {
            nickname: parts[0][1..].to_string(),
            homeserver: parts[1].to_string()
        }
    }
}

#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct RoomID {
    pub id: String,
    pub homeserver: String
}

impl fmt::Display for RoomID {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "!{}:{}", self.id, self.homeserver)
    }
}

impl RoomID {
    pub fn from_str(s: &str) -> Self {
        let parts: Vec<&str> = s.split(":").collect();
        RoomID {
            id: parts[0][1..].to_string(),
            homeserver: parts[1].to_string()
        }
    }
}

#[derive(Debug)]
pub enum MembershipAction {
    Join,
    Leave,
    Ban,
    Invite,
}

impl MembershipAction {
    pub fn from_str(s: &str) -> Self {
        match s {
            "join" => MembershipAction::Join,
            "leave" => MembershipAction::Leave,
            "ban" => MembershipAction::Ban,
            "invite" => MembershipAction::Invite,
            _ => panic!("unknown membership action {:?}", s)
        }
    }
}

#[derive(Debug)]
pub enum RoomEvent {
    CanonicalAlias(String),
    JoinRules(String),
    Membership(UserID, MembershipAction),
    HistoryVisibility(String),
    Create,
    Aliases,
    Message(UserID, String),
    PowerLevels
}

#[derive(Debug)]
pub struct TypingEvent {
    pub users: Vec<UserID>,
    pub room: RoomID,
}

#[derive(Debug)]
pub enum EventData {
    Room(RoomID, RoomEvent),
    Typing(TypingEvent),
    Presence(PresenceEvent)
}

impl EventData {
    pub fn type_str(&self) -> &'static str {
        match self {
            &EventData::Room(_, RoomEvent::Message(_, _)) => {
                "m.room.message"
            },
            _ => unreachable!()
        }
    }

    pub fn to_json(&self) -> json::Json {
        let mut ret = json::Object::new();
        match self {
            &EventData::Room(ref id, ref evt) => {
                match evt {
                    &RoomEvent::Message(ref sender, ref text) => {
                        ret.insert("msgtype".to_string(), json::Json::String("m.text".to_string()));
                        ret.insert("body".to_string(), json::Json::String(text.clone()));
                    },
                    _ => unreachable!()
                }
            },
            _ => unreachable!()
        }
        json::Json::Object(ret)
    }
}

#[derive(Debug)]
pub struct Event {
    pub id: Option<EventID>,
    pub data: EventData
}

#[derive(Debug)]
pub struct PresenceEvent {
    pub presence: String,
    pub user: UserID
}

impl Event {
    pub fn from_json(json: &Json) -> Self {
        let tokens: Vec<&str> = mjson::string(json, "type").trim().split(".").collect();
        assert!(tokens[0] == "m");
        let id = match json.as_object().unwrap().get("event_id") {
            Some(i) => Some(EventID::from_str(i.as_string().unwrap())),
            None => None
        };
        Event {
            id: id,
            data: match tokens[1] {
                "room" =>
                    Self::from_room_json(tokens[2], json),
                "typing" =>
                    EventData::Typing(TypingEvent {
                        users: vec![],
                        room: RoomID::from_str(mjson::string(json, "room_id"))
                    }),
                "presence" =>
                    EventData::Presence(PresenceEvent{
                        presence: mjson::string(json, "content.presence").to_string(),
                        user: UserID::from_str(mjson::string(json, "content.user_id"))
                    }),
                e => panic!("Unknown event {:?}!\nRaw JSON: {:?}", e, json)
            }
        }
    }

    fn from_room_json(event_type: &str, json: &Json) -> EventData {
        EventData::Room(
            RoomID::from_str(mjson::string(json, "room_id")),
            match event_type {
                "canonical_alias" =>
                    RoomEvent::CanonicalAlias(mjson::string(json, "content.alias").to_string()),
                "join_rules" =>
                    RoomEvent::JoinRules(mjson::string(json, "content.join_rule").to_string()),
                "member" =>
                    RoomEvent::Membership(UserID::from_str(mjson::string(json, "user_id")), MembershipAction::from_str(mjson::string(json, "content.membership"))),
                "history_visibility" =>
                    RoomEvent::HistoryVisibility(mjson::string(json, "content.history_visibility").to_string()),
                "create" =>
                    RoomEvent::Create,
                "aliases" =>
                    RoomEvent::Aliases,
                "power_levels" =>
                    RoomEvent::PowerLevels,
                "message" =>
                    RoomEvent::Message(UserID::from_str(mjson::string(json, "user_id")), mjson::string(json, "content.body").to_string()),
                e => panic!("Unknown room event {:?}: {:?}", e, json)
            }
        )
    }
}
<commit_msg>matrix: events: rooms: handle name events<commit_after>use rustc_serialize::json::Json;
use rustc_serialize::json;
use matrix::json as mjson;
use std::fmt;

#[derive(Clone, Debug, PartialEq)]
pub struct EventID {
    pub id: String,
    pub homeserver: String
}

impl EventID {
    pub fn from_str(s: &str) -> Self {
        let parts: Vec<&str> = s.split(":").collect();
        EventID {
            id: parts[0][1..].to_string(),
            homeserver: parts[1].to_string()
        }
    }
}

#[derive(Clone, Debug)]
pub struct UserID {
    pub nickname: String,
    pub homeserver: String
}

impl UserID {
    pub fn from_str(s: &str) -> Self {
        let parts: Vec<&str> = s.split(":").collect();
        UserID {
            nickname: parts[0][1..].to_string(),
            homeserver: parts[1].to_string()
        }
    }
}

#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct RoomID {
    pub id: String,
    pub homeserver: String
}

impl fmt::Display for RoomID {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "!{}:{}", self.id, self.homeserver)
    }
}

impl RoomID {
    pub fn from_str(s: &str) -> Self {
        let parts: Vec<&str> = s.split(":").collect();
        RoomID {
            id: parts[0][1..].to_string(),
            homeserver: parts[1].to_string()
        }
    }
}

#[derive(Debug)]
pub enum MembershipAction {
    Join,
    Leave,
    Ban,
    Invite,
}

impl MembershipAction {
    pub fn from_str(s: &str) -> Self {
        match s {
            "join" => MembershipAction::Join,
            "leave" => MembershipAction::Leave,
            "ban" => MembershipAction::Ban,
            "invite" => MembershipAction::Invite,
            _ => panic!("unknown membership action {:?}", s)
        }
    }
}

#[derive(Debug)]
pub enum RoomEvent {
    CanonicalAlias(String),
    JoinRules(String),
    Membership(UserID, MembershipAction),
    HistoryVisibility(String),
    Create,
    Aliases,
    Message(UserID, String),
    PowerLevels,
    Name(UserID, String)
}

#[derive(Debug)]
pub struct TypingEvent {
    pub users: Vec<UserID>,
    pub room: RoomID,
}

#[derive(Debug)]
pub enum EventData {
    Room(RoomID, RoomEvent),
    Typing(TypingEvent),
    Presence(PresenceEvent)
}

impl EventData {
    pub fn type_str(&self) -> &'static str {
        match self {
            &EventData::Room(_, RoomEvent::Message(_, _)) => {
                "m.room.message"
            },
            _ => unreachable!()
        }
    }

    pub fn to_json(&self) -> json::Json {
        let mut ret = json::Object::new();
        match self {
            &EventData::Room(ref id, ref evt) => {
                match evt {
                    &RoomEvent::Message(ref sender, ref text) => {
                        ret.insert("msgtype".to_string(), json::Json::String("m.text".to_string()));
                        ret.insert("body".to_string(), json::Json::String(text.clone()));
                    },
                    _ => unreachable!()
                }
            },
            _ => unreachable!()
        }
        json::Json::Object(ret)
    }
}

#[derive(Debug)]
pub struct Event {
    pub id: Option<EventID>,
    pub data: EventData
}

#[derive(Debug)]
pub struct PresenceEvent {
    pub presence: String,
    pub user: UserID
}

impl Event {
    pub fn from_json(json: &Json) -> Self {
        let tokens: Vec<&str> = mjson::string(json, "type").trim().split(".").collect();
        assert!(tokens[0] == "m");
        let id = match json.as_object().unwrap().get("event_id") {
            Some(i) => Some(EventID::from_str(i.as_string().unwrap())),
            None => None
        };
        Event {
            id: id,
            data: match tokens[1] {
                "room" =>
                    Self::from_room_json(tokens[2], json),
                "typing" =>
                    EventData::Typing(TypingEvent {
                        users: vec![],
                        room: RoomID::from_str(mjson::string(json, "room_id"))
                    }),
                "presence" =>
                    EventData::Presence(PresenceEvent{
                        presence: mjson::string(json, "content.presence").to_string(),
                        user: UserID::from_str(mjson::string(json, "content.user_id"))
                    }),
                e => panic!("Unknown event {:?}!\nRaw JSON: {:?}", e, json)
            }
        }
    }

    fn from_room_json(event_type: &str, json: &Json) -> EventData {
        EventData::Room(
            RoomID::from_str(mjson::string(json, "room_id")),
            match event_type {
                "canonical_alias" =>
                    RoomEvent::CanonicalAlias(mjson::string(json, "content.alias").to_string()),
                "join_rules" =>
                    RoomEvent::JoinRules(mjson::string(json, "content.join_rule").to_string()),
                "member" =>
                    RoomEvent::Membership(UserID::from_str(mjson::string(json, "user_id")), MembershipAction::from_str(mjson::string(json, "content.membership"))),
                "history_visibility" =>
                    RoomEvent::HistoryVisibility(mjson::string(json, "content.history_visibility").to_string()),
                "create" =>
                    RoomEvent::Create,
                "aliases" =>
                    RoomEvent::Aliases,
                "power_levels" =>
                    RoomEvent::PowerLevels,
                "message" =>
                    RoomEvent::Message(UserID::from_str(mjson::string(json, "user_id")), mjson::string(json, "content.body").to_string()),
                "name" =>
                    RoomEvent::Name(UserID::from_str(mjson::string(json, "user_id")), mjson::string(json, "content.name").to_string()),
                e => panic!("Unknown room event {:?}: {:?}", e, json)
            }
        )
    }
}
<|endoftext|>


<commit_before>extern crate ffmpeg;

use std::path::Path;

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

pub trait VideoNotifiable {
    fn new_video_frame(&mut self, ffmpeg::frame::Video);
}
pub trait AudioNotifiable {
    fn new_audio_frame(&mut self, ffmpeg::frame::Audio);
}

pub struct Context {
    pub ffmpeg_context: ffmpeg::format::context::Input,
    pub name: String,
    pub description: String,

    pub video_stream: Option<usize>,
    pub video_decoder: Option<ffmpeg::codec::decoder::Video>,
    pub video_notifiable: Option<Weak<RefCell<VideoNotifiable>>>,

    pub audio_stream: Option<usize>,
    pub audio_decoder: Option<ffmpeg::codec::decoder::Audio>,
    pub audio_notifiable: Option<Weak<RefCell<AudioNotifiable>>>,
}

fn print_packet_content(stream: &ffmpeg::format::stream::Stream, packet: &ffmpeg::codec::packet::Packet) {
    println!("\n* Packet for {:?} stream: {}", stream.disposition(), stream.index());
    println!("\tsize: {} - duration: {}, is key: {}",
             packet.size(), packet.duration(), packet.is_key(),
    );
    match packet.pts() {
        Some(pts) => println!("\tpts: {}", pts),
        None => (),
    }
    match packet.dts() {
        Some(dts) => println!("\tdts: {}", dts),
        None => (),
    }
    if let Some(data) = packet.data() {
        println!("\tfound data with len: {}", data.len());
    }
    let side_data_iter = stream.side_data();
    let side_data_len = side_data_iter.size_hint().0;
    if side_data_len > 0 {
        println!("\tside data nb: {}", side_data_len);
    }

    let decoder = stream.codec().decoder();
    match decoder.medium() {
        ffmpeg::media::Type::Video => match decoder.video() {
            Ok(video) => println!("\tvideo decoder: {:?}, width: {}, height: {}",
                                  video.format(), video.width(), video.height()),
            Err(_) => (),
        },
        ffmpeg::media::Type::Audio => match decoder.audio() {
            Ok(audio) => println!("\taudio decoder: {:?}, channels: {}, frame count: {}",
                                  audio.format(), audio.channels(), audio.frames()),
            Err(_) => (),
        },
        _ => (),
    }
}

impl Context {
    pub fn new(path: &Path) -> Result<Context, String> {
        match ffmpeg::format::input(&path) {
            Ok(ffmpeg_context) => {
                let mut new_ctx = Context{
                    ffmpeg_context: ffmpeg_context,
                    name: String::new(),
                    description: String::new(),

                    video_stream: None,
                    video_decoder: None,
                    video_notifiable: None,

                    audio_stream: None,
                    audio_decoder: None,
                    audio_notifiable: None,
                };

                {
                    let format = new_ctx.ffmpeg_context.format();
                    new_ctx.name = String::from(format.name());
                    new_ctx.description = String::from(format.description());

                    new_ctx.init_video_decoder();
                    new_ctx.init_audio_decoder();
                }

                // TODO: process metadata

                // TODO: see what we should do with subtitles

                println!("\n*** New media - Input: {} - {}", &new_ctx.name, &new_ctx.description);

                //new_ctx.preview();

                if new_ctx.video_stream.is_some() || new_ctx.audio_stream.is_some() {
                    // TODO: also check for misdetections (detection score)
                    Ok(new_ctx)
                }
                else {
                    Err("Couldn't find any video or audio stream".to_owned())
                }
            },
            Err(error) => {
                Err(format!("{:?}", error))
            },
        }
    }

    pub fn init_video_decoder(&mut self) {
        let stream = match self.ffmpeg_context.streams().best(ffmpeg::media::Type::Video) {
            Some(best_stream) => {
                println!("\nFound video stream with id: {}", best_stream.index());
                best_stream
            },
            None => {
                println!("No video stream");
                return;
            },
        };

        match stream.codec().decoder().video() {
            Ok(mut decoder) => {
                match decoder.set_parameters(stream.parameters()) {
                    Ok(_) => {
                        println!("\tinitialzed video decoder: {:?}", decoder.format());
                    },
                    Err(error) => panic!("Failed to set parameters for video decoder: {:?}", error),
                }

                self.video_stream = Some(stream.index());
                self.video_decoder = Some(decoder);
            },
            Err(error) => panic!("Failed to get video decoder: {:?}", error),
        }
    }

    pub fn init_audio_decoder(&mut self) {
        let stream = match self.ffmpeg_context.streams().best(ffmpeg::media::Type::Audio) {
            Some(best_stream) => {
                println!("\nFound audio stream with id: {}", best_stream.index());
                best_stream
            },
            None => {
                println!("No audio stream");
                return;
            },
        };

        match stream.codec().decoder().audio() {
            Ok(mut decoder) => {
                match decoder.set_parameters(stream.parameters()) {
                    Ok(_) => {
                        println!("\tinitialzed audio decoder: {:?} - channels: {}", decoder.format(), decoder.channels());
                    },
                    Err(error) => panic!("Failed to set parameters for audio decoder: {:?}", error),
                }

                self.audio_stream = Some(stream.index());
                self.audio_decoder = Some(decoder);
            },
            Err(error) => panic!("Failed to get audio decoder: {:?}", error),
        }
    }

    pub fn register_video_notifiable(&mut self, notifiable: Rc<RefCell<VideoNotifiable>>) {
        self.video_notifiable = Some(Rc::downgrade(&notifiable));
    }

    pub fn register_audio_notifiable(&mut self, notifiable: Rc<RefCell<AudioNotifiable>>) {
        self.audio_notifiable = Some(Rc::downgrade(&notifiable));
    }

    pub fn preview(&mut self) {
        let mut frames_processed = 0;
        let mut expected_frames = 0;
        if self.video_stream.is_some() {
            expected_frames += 1;
        }
        if self.audio_stream.is_some() {
            expected_frames += 1;
        }

        let mut video_frame = ffmpeg::frame::Video::empty();
        let mut audio_frame = ffmpeg::frame::Audio::empty();

        for (stream, packet) in self.ffmpeg_context.packets() {
            print_packet_content(&stream, &packet);
            let mut got_frame = false;
            let decoder = stream.codec().decoder();
            match decoder.medium() {
                ffmpeg::media::Type::Video => match self.video_stream {
                    Some(stream_index) => {
                        if stream_index == stream.index() {
                            let mut video = match stream.codec().decoder().video() {
                                Ok(decoder) => decoder,
                                Err(error) => panic!("Error getting video decoder for stream {}: {:?}", stream_index, error),
                            };
                            /*
                            let mut video = match self.video_decoder {
                                Some(ref mut decoder) => decoder,
                                None => panic!("Error getting video decoder for stream {}", stream_index),
                            };
                            */
                            match video.decode(&packet, &mut video_frame) {
                                Ok(decode_got_frame) =>  {
                                    got_frame = decode_got_frame;
                                    let planes = video_frame.planes();
                                    println!("\tdecoded video frame, found {} planes - got frame: {}", planes, got_frame);
                                    for index in 0..planes {
                                        println!("\tplane: {} - data len: {}", index, video_frame.data(index).len());
                                    }
                                },
                                Err(error) => println!("Error decoding video packet for stream {}: {:?}", stream_index, error),
                            }
                            if got_frame {
                                frames_processed += 1;
                                match self.video_notifiable.as_ref() {
                                    Some(notifiable_weak) => {
                                        match notifiable_weak.upgrade() {
                                            Some(notifiable) => {
                                                notifiable.borrow_mut().new_video_frame(video_frame);
                                                video_frame = ffmpeg::frame::Video::empty();
                                            },
                                            None => (),
                                        }
                                    },
                                    None => (),
                                }
                            }
                        }
                        else {
                            println!("Skipping stream {}", stream.index());
                        }
                    },
                    None => panic!("No video decoder"),
                },
                ffmpeg::media::Type::Audio => match self.audio_stream {
                    Some(stream_index) => {
                        if stream_index == stream.index() {
                            let mut audio = match stream.codec().decoder().audio() {
                                Ok(decoder) => decoder,
                                Err(error) => panic!("Error getting audio decoder for stream {}: {:?}", stream_index, error),
                            };
                            /*
                            let mut audio = match self.audio_decoder {
                                Some(ref mut decoder) => decoder,
                                None => panic!("Error getting audio decoder for stream {}", stream_index),
                            };
                            */
                            match audio.decode(&packet, &mut audio_frame) {
                                Ok(decode_got_frame) =>  {
                                    got_frame = decode_got_frame;
                                    let planes = audio_frame.planes();
                                    println!("\tdecoded audio frame, found {} planes - got frame: {}", planes, got_frame);
                                    for index in 0..planes {
                                        println!("\tplane: {} - data len: {}", index, audio_frame.data(index).len());
                                    }
                                },
                                Err(error) => panic!("Error decoding audio packet for stream {}: {:?}", stream_index, error),
                            }
                            if got_frame {
                                frames_processed += 1;
                                match self.audio_notifiable.as_ref() {
                                    Some(notifiable_weak) => {
                                        match notifiable_weak.upgrade() {
                                            Some(notifiable) => {
                                                notifiable.borrow_mut().new_audio_frame(audio_frame);
                                                audio_frame = ffmpeg::frame::Audio::empty();
                                            },
                                            None => (),
                                        }
                                    },
                                    None => (),
                                }
                            }
                        }
                        else {
                            println!("Skipping stream {}", stream.index());
                        }
                    },
                    None => panic!("No audio decoder"),
                },
                _ => (),
            }

            if frames_processed == expected_frames {
                break;
            }
        }
    }
}
<commit_msg>Fixed decoding of frames (#1)<commit_after>extern crate ffmpeg;

use std::path::Path;

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

pub trait VideoNotifiable {
    fn new_video_frame(&mut self, ffmpeg::frame::Video);
}
pub trait AudioNotifiable {
    fn new_audio_frame(&mut self, ffmpeg::frame::Audio);
}

pub struct Context {
    pub ffmpeg_context: ffmpeg::format::context::Input,
    pub path: String,
    pub name: String,
    pub description: String,

    pub video_stream: Option<usize>,
    pub video_decoder: Option<ffmpeg::codec::decoder::Video>,
    pub video_notifiable: Option<Weak<RefCell<VideoNotifiable>>>,

    pub audio_stream: Option<usize>,
    pub audio_decoder: Option<ffmpeg::codec::decoder::Audio>,
    pub audio_notifiable: Option<Weak<RefCell<AudioNotifiable>>>,
}

fn print_packet_content(stream: &ffmpeg::format::stream::Stream, packet: &ffmpeg::codec::packet::Packet) {
    println!("\n* Packet for {:?} stream: {}", stream.disposition(), stream.index());
    println!("\tsize: {} - duration: {}, is key: {}",
             packet.size(), packet.duration(), packet.is_key(),
    );
    match packet.pts() {
        Some(pts) => println!("\tpts: {}", pts),
        None => (),
    }
    match packet.dts() {
        Some(dts) => println!("\tdts: {}", dts),
        None => (),
    }
    if let Some(data) = packet.data() {
        println!("\tfound data with len: {}", data.len());
    }
    let side_data_iter = stream.side_data();
    let side_data_len = side_data_iter.size_hint().0;
    if side_data_len > 0 {
        println!("\tside data nb: {}", side_data_len);
    }

    let decoder = stream.codec().decoder();
    match decoder.medium() {
        ffmpeg::media::Type::Video => match decoder.video() {
            Ok(video) => println!("\tvideo decoder: {:?}, width: {}, height: {}",
                                  video.format(), video.width(), video.height()),
            Err(_) => (),
        },
        ffmpeg::media::Type::Audio => match decoder.audio() {
            Ok(audio) => println!("\taudio decoder: {:?}, channels: {}, frame count: {}",
                                  audio.format(), audio.channels(), audio.frames()),
            Err(_) => (),
        },
        _ => (),
    }
}

impl Context {
    pub fn new(path: &Path) -> Result<Context, String> {
        match ffmpeg::format::input(&path) {
            Ok(ffmpeg_context) => {
                let mut new_ctx = Context{
                    ffmpeg_context: ffmpeg_context,
                    path: String::from(path.to_str().unwrap()),
                    name: String::new(),
                    description: String::new(),

                    video_stream: None,
                    video_decoder: None,
                    video_notifiable: None,

                    audio_stream: None,
                    audio_decoder: None,
                    audio_notifiable: None,
                };

                {
                    let format = new_ctx.ffmpeg_context.format();
                    new_ctx.name = String::from(format.name());
                    new_ctx.description = String::from(format.description());

                    new_ctx.init_video_decoder();
                    new_ctx.init_audio_decoder();
                }

                // TODO: process metadata

                // TODO: see what we should do with subtitles

                println!("\n*** New media - Input: {} - {}", &new_ctx.name, &new_ctx.description);

                //new_ctx.preview();

                if new_ctx.video_stream.is_some() || new_ctx.audio_stream.is_some() {
                    // TODO: also check for misdetections (detection score)
                    Ok(new_ctx)
                }
                else {
                    Err("Couldn't find any video or audio stream".to_owned())
                }
            },
            Err(error) => {
                Err(format!("{:?}", error))
            },
        }
    }

    pub fn init_video_decoder(&mut self) {
        let stream = match self.ffmpeg_context.streams().best(ffmpeg::media::Type::Video) {
            Some(best_stream) => {
                println!("\nFound video stream with id: {}", best_stream.index());
                best_stream
            },
            None => {
                println!("No video stream");
                return;
            },
        };

        match stream.codec().decoder().video() {
            Ok(mut decoder) => {
                match decoder.set_parameters(stream.parameters()) {
                    Ok(_) => {
                        println!("\tinitialzed video decoder: {:?}", decoder.format());
                    },
                    Err(error) => panic!("Failed to set parameters for video decoder: {:?}", error),
                }

                self.video_stream = Some(stream.index());
                self.video_decoder = Some(decoder);
            },
            Err(error) => panic!("Failed to get video decoder: {:?}", error),
        }
    }

    pub fn init_audio_decoder(&mut self) {
        let stream = match self.ffmpeg_context.streams().best(ffmpeg::media::Type::Audio) {
            Some(best_stream) => {
                println!("\nFound audio stream with id: {}", best_stream.index());
                best_stream
            },
            None => {
                println!("No audio stream");
                return;
            },
        };

        match stream.codec().decoder().audio() {
            Ok(mut decoder) => {
                match decoder.set_parameters(stream.parameters()) {
                    Ok(_) => {
                        println!("\tinitialzed audio decoder: {:?} - channels: {}", decoder.format(), decoder.channels());
                    },
                    Err(error) => panic!("Failed to set parameters for audio decoder: {:?}", error),
                }

                self.audio_stream = Some(stream.index());
                self.audio_decoder = Some(decoder);
            },
            Err(error) => panic!("Failed to get audio decoder: {:?}", error),
        }
    }

    pub fn register_video_notifiable(&mut self, notifiable: Rc<RefCell<VideoNotifiable>>) {
        self.video_notifiable = Some(Rc::downgrade(&notifiable));
    }

    pub fn register_audio_notifiable(&mut self, notifiable: Rc<RefCell<AudioNotifiable>>) {
        self.audio_notifiable = Some(Rc::downgrade(&notifiable));
    }

    pub fn preview(&mut self) {
        // TODO: better trace streams processed (use a HashSet as before)
        let mut frames_processed = 0;
        let mut expected_frames = 0;
        if self.video_stream.is_some() {
            expected_frames += 1;
        }
        if self.audio_stream.is_some() {
            expected_frames += 1;
        }

        let mut video_frame = ffmpeg::frame::Video::empty();
        let mut audio_frame = ffmpeg::frame::Audio::empty();

        for (stream, packet) in self.ffmpeg_context.packets() {
            //print_packet_content(&stream, &packet); // TODO: fix this function which corrupts the decoder
            let mut got_frame = false;
            let decoder = stream.codec().decoder();
            match decoder.medium() {
                ffmpeg::media::Type::Video => match self.video_stream {
                    Some(stream_index) => {
                        if stream_index == stream.index() {
                            let mut video = match self.video_decoder {
                                Some(ref mut decoder) => decoder,
                                None => panic!("Error getting video decoder for stream {}", stream_index),
                            };
                            match video.decode(&packet, &mut video_frame) {
                                Ok(decode_got_frame) =>  {
                                    got_frame = decode_got_frame;
                                    let planes = video_frame.planes();
                                    println!("\tdecoded video frame, found {} planes - got frame: {}", planes, got_frame);
                                    for index in 0..planes {
                                        println!("\tplane: {} - data len: {}", index, video_frame.data(index).len());
                                    }
                                },
                                Err(error) => println!("Error decoding video packet for stream {}: {:?}", stream_index, error),
                            }
                            if got_frame {
                                frames_processed += 1;
                                match self.video_notifiable.as_ref() {
                                    Some(notifiable_weak) => {
                                        match notifiable_weak.upgrade() {
                                            Some(notifiable) => {
                                                notifiable.borrow_mut().new_video_frame(video_frame);
                                                video_frame = ffmpeg::frame::Video::empty();
                                            },
                                            None => (),
                                        }
                                    },
                                    None => (),
                                }
                            }
                        }
                        else {
                            println!("Skipping stream {}", stream.index());
                        }
                    },
                    None => panic!("No video decoder"),
                },
                ffmpeg::media::Type::Audio => match self.audio_stream {
                    Some(stream_index) => {
                        if stream_index == stream.index() {
                            let ref mut audio = match self.audio_decoder.as_mut() {
                                Some(decoder) => decoder,
                                None => panic!("Error getting audio decoder for stream {}", stream_index),
                            };
                            match audio.decode(&packet, &mut audio_frame) {
                                Ok(decode_got_frame) =>  {
                                    got_frame = decode_got_frame;
                                    let planes = audio_frame.planes();
                                    println!("\tdecoded audio frame, found {} planes - got frame: {}", planes, got_frame);
                                    for index in 0..planes {
                                        println!("\tplane: {} - data len: {}", index, audio_frame.data(index).len());
                                    }
                                },
                                Err(error) => panic!("Error decoding audio packet for stream {}: {:?}", stream_index, error),
                            }
                            if got_frame {
                                frames_processed += 1;
                                match self.audio_notifiable.as_ref() {
                                    Some(notifiable_weak) => {
                                        match notifiable_weak.upgrade() {
                                            Some(notifiable) => {
                                                notifiable.borrow_mut().new_audio_frame(audio_frame);
                                                audio_frame = ffmpeg::frame::Audio::empty();
                                            },
                                            None => (),
                                        }
                                    },
                                    None => (),
                                }
                            }
                        }
                        else {
                            println!("Skipping stream {}", stream.index());
                        }
                    },
                    None => panic!("No audio decoder"),
                },
                _ => (),
            }

            if frames_processed == expected_frames {
                break;
            }
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 The Exonum Team
//
// 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.

//! `encoding` is a lazy serialization library,
//! it allows to keep struct serialized in place, and deserialize fields on demand.
//!
//! Binary representation of structure is split into two main parts:
//!
//! - Header - fixed sized part.
//! - Body - dynamic sized, known only after parsing header, part.
//!
//! For easy creating this structures,
//! in exonum you can use macros `message!` and `encoding_struct!`
//! #Examples
//! Imagine structure with just two field's
//!
//! - First one is `String`
//! - second one is `u64`
//!
//! Then to create, for example [storage value](../macro.encoding_struct.html),
//! you need to use macros like this:
//!
//! ```
//! # #[macro_use] extern crate exonum;
//! # extern crate serde;
//! # extern crate serde_json;
//! encoding_struct! {
//!     struct MyAwesomeStructure {
//!         name: &str,
//!         age: u64,
//!     }
//! }
//! // now if we create it in memory
//!
//! # fn main() {
//!     let student = MyAwesomeStructure::new("Andrew", 23);
//! # drop(student);
//! # }
//! ```
//! Then in internal buffer of `student` you will get:
//!
//! | Position | Stored data  | Hexadecimal form | Comment |
//! |:--------|:------:|:---------------------|:--------------------------------------------------|
//! `0  => 4`  | 16    | `10 00 00 00`            | LE stored segment pointer to the data |
//! `4  => 8`  | 6     | `06 00 00 00`            | LE stored segment size |
//! `8  => 16` | 23    | `17 00 00 00 00 00 00 00`| number in little endian |
//! `16 => 24` | Andrew| `41 6e 64 72 65 77`	    | Real text bytes|
//!
//!
//! #Fields layout
//! Fields could be splitted into tree main parts:
//!
//! ### Primitive types
//!
//! Primitive types are all fixed sized, and located fully in header.
// TODO explain how an signed integer is stored in memory (what codding) (ECR-155)
//!
//! | Type name | Size in Header | Info |
//! |:--------|:---------------------|:--------------------------------------------------|
//! `u8`     | 1    | Regular byte  |
//! `i8`     | 1    | Signed byte  |
//! `u16`    | 2    | Short unsigned number stored in little endian  |
//! `i16`    | 2    | Short signed number stored in little endian  |
//! `u32`    | 4    | 32-bit unsigned number stored in little endian  |
//! `i32`    | 4    | 32-bit signed number stored in little endian  |
//! `u64`    | 8    | long unsigned number stored in little endian  |
//! `i64`    | 8    | long signed number stored in little endian  |
//! `F32`    | 4    | 32-bit floating point type stored in little endian [\[1\]](#1)[\[2\]](#2)|
//! `F64`    | 8    | 64-bit floating point type stored in little endian [\[1\]](#1)[\[2\]](#2)|
//! `bool`   | 1    | stored as single byte, where `0x01` - true `0x00` - false [\[3\]](#3)|
//!
//! ######\[1]
//! Special floating point values that cannot be represented as sequences of digits (such as
//! Infinity, NaN and signaling NaN) are not permitted.
//!
//! ######\[2]
//! Floating point values serialization is hidden behind the feature gate `float_serialize`.
//!
//! ######\[3]
//! **Trying to represent other values as bool leads to undefined behavior**.
//!
//! ### Segment fields
//!
//! All segment types took 8 bytes in header,
//! 4 for position in buffer,
//! and 4 for segment field size
//!
//! ### Custom fields
//!
//! This types could be implemented as creator want,
//! but they should declare how many bytes they
//! will write on header [in function `field_size()`](./trait.Field.html#tymethod.field_size)
//!

use std::convert::From;
use std::ops::{Add, Sub, Mul, Div};

pub use self::fields::Field;
pub use self::segments::SegmentField;
pub use self::error::Error;
#[cfg(feature = "float_serialize")]
pub use self::float::{F32, F64};

#[macro_use]
pub mod serialize;

mod error;
#[macro_use]
mod fields;
mod segments;
#[macro_use]
mod spec;
#[cfg(feature = "float_serialize")]
mod float;

#[cfg(test)]
mod tests;

/// Type alias usable for reference in buffer
pub type Offset = u32;

/// Type alias that should be returned in `check` method of `Field`
pub type Result = ::std::result::Result<CheckedOffset, Error>;

// TODO replace by more generic type (ECR-156).
/// `CheckedOffset` is a type that take control over overflow,
/// so you can't panic without `unwrap`,
/// and work with this value without overflow checks.
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
pub struct CheckedOffset {
    offset: Offset,
}

impl CheckedOffset {
    /// create checked value
    pub fn new(offset: Offset) -> CheckedOffset {
        CheckedOffset { offset: offset }
    }

    /// return unchecked offset
    pub fn unchecked_offset(self) -> Offset {
        self.offset
    }
}

macro_rules! implement_default_ops_checked {
    ($trait_name: ident $function:ident $checked_function:ident) => (
        impl $trait_name<CheckedOffset> for CheckedOffset {
            type Output = ::std::result::Result<CheckedOffset, Error>;
            fn $function(self, rhs: CheckedOffset) -> Self::Output {
                self.offset.$checked_function(rhs.offset)
                        .map(CheckedOffset::new)
                        .ok_or(Error::OffsetOverflow)
            }
        }
        impl $trait_name<Offset> for CheckedOffset {
            type Output = ::std::result::Result<CheckedOffset, Error>;
            fn $function(self, rhs: Offset) -> Self::Output {
                self.offset.$checked_function(rhs)
                        .map(CheckedOffset::new)
                        .ok_or(Error::OffsetOverflow)
            }
        }
    )
}

implement_default_ops_checked!{Add add checked_add }
implement_default_ops_checked!{Sub sub checked_sub }
implement_default_ops_checked!{Mul mul checked_mul }
implement_default_ops_checked!{Div div checked_div }

impl From<Offset> for CheckedOffset {
    fn from(offset: Offset) -> CheckedOffset {
        CheckedOffset::new(offset)
    }
}
<commit_msg>Rewrite `encoding` module docs<commit_after>// Copyright 2017 The Exonum Team
//
// 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.

//! `encoding` is a lazy serialization library supporting zero-copy (de)serialization
//! of primitive types, heterogeneous structures and arrays.
//!
//! # Structure serialization
//!
//! Structures are in the root of any serializable Exonum object.
//! Binary representation of structures is split into two main parts:
//!
//! - **Header:** a fixed-sized part
//! - **Body:** dynamic-sized part, known only after parsing the header
//!
//! To create a structure type, you can use [`message!`] and [`encoding_struct!`] macros.
//!
//! [`message!`]: ../macro.message.html
//! [`encoding_struct!`]: ../macro.encoding_struct.html
//!
//! # Examples
//!
//! Consider a structure with two fields: a `String` and a `u64`.
//! To implement Exonum (de)serialization for this structure
//! you need to use macros like this:
//!
//! ```
//! # #[macro_use] extern crate exonum;
//! # extern crate serde;
//! # extern crate serde_json;
//! encoding_struct! {
//!     struct MyAwesomeStructure {
//!         name: &str,
//!         age: u64,
//!     }
//! }
//!
//! # fn main() {
//! let student = MyAwesomeStructure::new("Andrew", 23);
//! # drop(student);
//! # }
//! ```
//!
//! Then the internal buffer of `student` is as follows:
//!
//! | Position | Stored data | Hexadecimal form | Comment |
//! |:--------|:------:|:---------------------|:------------------------------------------|
//! | `0  => 4`  | 16    | `10 00 00 00`            | LE-encoded segment pointer to the data |
//! | `4  => 8`  | 6     | `06 00 00 00`            | LE-encoded segment size |
//! | `8  => 16` | 23    | `17 00 00 00 00 00 00 00` | number in little endian |
//! | `16 => 24` | Andrew | `41 6e 64 72 65 77` | Text bytes in UTF-8 encoding |
//!
//! # Structure fields
//!
//! ## Primitive types
//!
//! Primitive types are all fixed-sized, and located fully in the header.
// TODO explain how an signed integer is stored in memory (what codding) (ECR-155)
//!
//! | Type name | Size in Header | Info |
//! |:--------|:---------------------|:--------------------------------------------------|
//! | `u8`     | 1    | Regular byte  |
//! | `i8`     | 1    | Signed byte  |
//! | `u16`    | 2    | Short unsigned integer stored in little endian  |
//! | `i16`    | 2    | Short signed integer stored in little endian  |
//! | `u32`    | 4    | 32-bit unsigned integer stored in little endian  |
//! | `i32`    | 4    | 32-bit signed integer stored in little endian  |
//! | `u64`    | 8    | Long unsigned integer stored in little endian  |
//! | `i64`    | 8    | Long signed integer stored in little endian  |
//! | `F32`    | 4    | 32-bit floating point type stored in little endian \[1\]\[2\] |
//! | `F64`    | 8    | 64-bit floating point type stored in little endian \[1\]\[2\] |
//! | `bool`   | 1    | Stored as a byte, with `0x01` denoting true and `0x00` false \[3\] |
//!
//! \[1\]
//! Special floating point values that cannot be represented as sequences of digits (such as
//! Infinity, NaN and signaling NaN) are not permitted.
//!
//! \[2\]
//! Floating point value serialization is hidden behind the `float_serialize` feature gate.
//!
//! \[3\]
//! Trying to represent other values as `bool` leads to undefined behavior.
//!
//! ## Segment fields
//!
//! All segment types take 8 bytes in header: 4 for position in buffer,
//! and 4 for the segment field size.
//!
//! ## Custom fields
//!
//! These types could be implemented as per developer's design,
//! but they should declare how many bytes they
//! write in the header using the [`field_size()`] function.
//!
//! [`field_size()`]: ./trait.Field.html#tymethod.field_size

use std::convert::From;
use std::ops::{Add, Sub, Mul, Div};

pub use self::fields::Field;
pub use self::segments::SegmentField;
pub use self::error::Error;
#[cfg(feature = "float_serialize")]
pub use self::float::{F32, F64};

#[macro_use]
pub mod serialize;

mod error;
#[macro_use]
mod fields;
mod segments;
#[macro_use]
mod spec;
#[cfg(feature = "float_serialize")]
mod float;

#[cfg(test)]
mod tests;

/// Type alias usable for reference in buffer
pub type Offset = u32;

/// Type alias that should be returned in `check` method of `Field`
pub type Result = ::std::result::Result<CheckedOffset, Error>;

// TODO replace by more generic type (ECR-156).
/// `CheckedOffset` is a type that take control over overflow,
/// so you can't panic without `unwrap`,
/// and work with this value without overflow checks.
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
pub struct CheckedOffset {
    offset: Offset,
}

impl CheckedOffset {
    /// create checked value
    pub fn new(offset: Offset) -> CheckedOffset {
        CheckedOffset { offset: offset }
    }

    /// return unchecked offset
    pub fn unchecked_offset(self) -> Offset {
        self.offset
    }
}

macro_rules! implement_default_ops_checked {
    ($trait_name: ident $function:ident $checked_function:ident) => (
        impl $trait_name<CheckedOffset> for CheckedOffset {
            type Output = ::std::result::Result<CheckedOffset, Error>;
            fn $function(self, rhs: CheckedOffset) -> Self::Output {
                self.offset.$checked_function(rhs.offset)
                        .map(CheckedOffset::new)
                        .ok_or(Error::OffsetOverflow)
            }
        }
        impl $trait_name<Offset> for CheckedOffset {
            type Output = ::std::result::Result<CheckedOffset, Error>;
            fn $function(self, rhs: Offset) -> Self::Output {
                self.offset.$checked_function(rhs)
                        .map(CheckedOffset::new)
                        .ok_or(Error::OffsetOverflow)
            }
        }
    )
}

implement_default_ops_checked!{Add add checked_add }
implement_default_ops_checked!{Sub sub checked_sub }
implement_default_ops_checked!{Mul mul checked_mul }
implement_default_ops_checked!{Div div checked_div }

impl From<Offset> for CheckedOffset {
    fn from(offset: Offset) -> CheckedOffset {
        CheckedOffset::new(offset)
    }
}
<|endoftext|>


<commit_before>use super::definitions::{
    DataVectorDomain,
    ErrorReason,
    DataVector,
    VecResult,
    PaddingOption};
use RealNumber;
use super::{
    GenericDataVector,
    RealVectorOperations,
    GenericVectorOperations,
    ComplexVectorOperations,
    TimeDomainOperations,
    FrequencyDomainOperations,
    ComplexTimeVector,
    ComplexFreqVector};

/// Cross-correlation of data vectors. See also https://en.wikipedia.org/wiki/Cross-correlation
///
/// The correlation is calculated in two steps. This is done to give you more control over two things:
///
/// 1. Should the correlation use zero padding or not. This is done by calling either `prepare_argument`
///    or `prepare_argument_padded`.
/// 2. The lifetime of the argument. The argument needs to be transformed for the correlation and
///    depending on the application that might be just okay, a clone needs to be created or
///    it's okay to use one argument for multiple correlations.
///
/// To get the same behavior like GNU Octave or MATLAB `prepare_argument_padded` needs to be
/// called before doing the correlation. See also the example section for how to do this.
/// # Example
///
/// ```
/// use basic_dsp::{ComplexTimeVector32, CrossCorrelation, DataVector};
/// let vector = ComplexTimeVector32::from_interleaved(&[1.0, 1.0, 2.0, 2.0, 3.0, 3.0]);
/// let argument = ComplexTimeVector32::from_interleaved(&[3.0, 3.0, 2.0, 2.0, 1.0, 1.0]);
/// let argument = argument.prepare_argument_padded().expect("Ignoring error handling in examples");
/// let result = vector.correlate(&argument).expect("Ignoring error handling in examples");
/// let expected = &[2.0, 0.0, 8.0, 0.0, 20.0, 0.0, 24.0, 0.0, 18.0, 0.0];
/// for i in 0..result.len() {
///     assert!((result[i] - expected[i]).abs() < 1e-4);
/// }
/// ```
/// # Unstable
/// This functionality has been recently added in order to find out if the definitions are consistent.
/// However the actual implementation is lacking tests.
/// # Failures
/// VecResult may report the following `ErrorReason` members:
///
/// 1. `VectorMustBeComplex`: if `self` is in real number space.
/// 3. `VectorMetaDataMustAgree`: in case `self` and `function` are not in the same number space and same domain.
pub trait CrossCorrelation<T> : DataVector<T>
    where T : RealNumber {
    type FreqPartner;
    /// Prepares an argument to be used for convolution. Preparing an argument includes two steps:
    ///
    /// 1. Calculate the plain FFT
    /// 2. Calculate the complex conjugate
    fn prepare_argument(self) -> VecResult<Self::FreqPartner>;

    /// Prepares an argument to be used for convolution. The argument is zero padded to length of `2 * self.points() - 1`
    /// and then the same operations are performed as described for `prepare_argument`.
    fn prepare_argument_padded(self) -> VecResult<Self::FreqPartner>;

    /// Calculates the correlation between `self` and `other`. `other` needs to be a time vector which
    /// went through one of the prepare functions `prepare_argument` or `prepare_argument_padded`. See also the
    /// trait description for more details.
    fn correlate(self, other: &Self::FreqPartner) -> VecResult<Self>;
}

macro_rules! define_correlation_impl {
    ($($data_type:ident,$reg:ident);*) => {
        $(
            impl CrossCorrelation<$data_type> for GenericDataVector<$data_type> {
                type FreqPartner = Self;

                fn prepare_argument(self) -> VecResult<Self::FreqPartner> {
                    self.plain_fft()
                    .and_then(|v|v.complex_conj())
                }

                fn prepare_argument_padded(self) -> VecResult<Self::FreqPartner> {
                    let points = self.points();
                    self.zero_pad(2 * points - 1, PaddingOption::Surround)
                    .and_then(|v|v.plain_fft())
                    .and_then(|v|v.complex_conj())
                }

                fn correlate(self, other: &Self::FreqPartner) -> VecResult<Self> {
                    assert_complex!(self);
                    assert_time!(self);
                    let points = other.points();
                    Ok(self)
                    .and_then(|v|v.zero_pad(points, PaddingOption::Surround))
                    .and_then(|v|v.plain_fft())
                    .and_then(|v|v.multiply_vector(&other))
                    .and_then(|v| {
                        let p = v.points();
                        v.real_scale(1.0 / p as $data_type)
                    })
                    .and_then(|v|v.plain_ifft())
                    .and_then(|v|v.swap_halves())
                }
            }
        )*
    }
}
define_correlation_impl!(f32, Reg32; f64, Reg64);

macro_rules! define_correlation_forward {
    ($($name:ident, $data_type:ident);*) => {
        $(
            impl CrossCorrelation<$data_type> for $name<$data_type> {
                type FreqPartner = ComplexFreqVector<$data_type>;
                fn prepare_argument(self) -> VecResult<Self::FreqPartner> {
                    Self::FreqPartner::from_genres(self.to_gen().prepare_argument())
                }

                fn prepare_argument_padded(self) -> VecResult<Self::FreqPartner> {
                    Self::FreqPartner::from_genres(self.to_gen().prepare_argument_padded())
                }

                fn correlate(self, other: &Self::FreqPartner) -> VecResult<Self> {
                    Self::from_genres(self.to_gen().correlate(other.to_gen_borrow()))
                }
            }
        )*
    }
}

define_correlation_forward!(
    ComplexTimeVector, f32; ComplexTimeVector, f64
);

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

    #[test]
    fn time_correlation_test() {
        let a = ComplexTimeVector32::from_interleaved(&[0.0800, 0.0, 0.1876, 0.1170, 0.4601, 0.4132, 0.7700, 0.7500, 0.9723, 0.9698, 0.9723, 0.9698, 0.7700, 0.7500, 0.4601, 0.4132, 0.1876, 0.1170, 0.0800, 0.0]);
        let b = ComplexTimeVector32::from_interleaved(&[0.1000, -0.6366, 0.3000, 0.0, 0.5000, 0.2122, 0.7000, 0.0, 0.9000, -0.1273, 0.9000, 0.0, 0.7000, 0.0909, 0.5000, 0.0, 0.3000, -0.0707, 0.1000, 0.0]);
        let c: &[f32] = &[0.0080, 0.0000, 0.0428, 0.0174, 0.1340, 0.0897, 0.3356, 0.2827, 0.7192, 0.6479, 1.3058, 1.1946, 2.0175, 1.8757,
                          2.7047, 2.5665, 3.2186, 3.0874, 3.4409, 3.2994, 3.2291, 3.1287, 2.5801, 2.7264, 1.7085, 2.1882, 0.8637, 1.6369,
                          0.2319, 1.1420, -0.0878, 0.7078, -0.1208, 0.3523, -0.0317, 0.1311, 0.0080, 0.0509];
        let b = b.prepare_argument_padded().unwrap();
        let res: ComplexTimeVector32 = a.correlate(&b).unwrap();
        let res = res.data();
        let tol = 0.1;
        for i in 0..c.len() {
            if (res[i] - c[i]).abs() > tol {
                panic!("assertion failed: {:?} != {:?} at index {}", res, c, i);
            }
        }
    }

    #[test]
    fn time_correlation_test2() {
        let a = ComplexTimeVector32::from_interleaved(&[1.0, 1.0, 2.0, 1.0, 3.0, 1.0]);
        let b = ComplexTimeVector32::from_interleaved(&[4.0, 1.0, 5.0, 1.0, 6.0, 1.0]);
        let c: &[f32] = &[7.0, 5.0, 19.0, 8.0, 35.0, 9.0, 25.0, 4.0, 13.0, 1.0];
        let b = b.prepare_argument_padded().unwrap();
        let res: ComplexTimeVector32 = a.correlate(&b).unwrap();
        let res = res.data();
        let tol = 0.1;
        for i in 0..c.len() {
            if (res[i] - c[i]).abs() > tol {
                panic!("assertion failed: {:?} != {:?} at index {}", res, c, i);
            }
        }
    }
}<commit_msg>Small documentation improvements<commit_after>use super::definitions::{
    DataVectorDomain,
    ErrorReason,
    DataVector,
    VecResult,
    PaddingOption};
use RealNumber;
use super::{
    GenericDataVector,
    RealVectorOperations,
    GenericVectorOperations,
    ComplexVectorOperations,
    TimeDomainOperations,
    FrequencyDomainOperations,
    ComplexTimeVector,
    ComplexFreqVector};

/// Cross-correlation of data vectors. See also https://en.wikipedia.org/wiki/Cross-correlation
///
/// The correlation is calculated in two steps. This is done to give you more control over two things:
///
/// 1. Should the correlation use zero padding or not? This is done by calling either `prepare_argument`
///    or `prepare_argument_padded`.
/// 2. The lifetime of the argument. The argument needs to be transformed for the correlation and
///    depending on the application that might be just fine, or a clone needs to be created or
///    it's okay to use one argument for multiple correlations.
///
/// To get the same behavior like GNU Octave or MATLAB `prepare_argument_padded` needs to be
/// called before doing the correlation. See also the example section for how to do this.
/// # Example
///
/// ```
/// use basic_dsp::{ComplexTimeVector32, CrossCorrelation, DataVector};
/// let vector = ComplexTimeVector32::from_interleaved(&[1.0, 1.0, 2.0, 2.0, 3.0, 3.0]);
/// let argument = ComplexTimeVector32::from_interleaved(&[3.0, 3.0, 2.0, 2.0, 1.0, 1.0]);
/// let argument = argument.prepare_argument_padded().expect("Ignoring error handling in examples");
/// let result = vector.correlate(&argument).expect("Ignoring error handling in examples");
/// let expected = &[2.0, 0.0, 8.0, 0.0, 20.0, 0.0, 24.0, 0.0, 18.0, 0.0];
/// for i in 0..result.len() {
///     assert!((result[i] - expected[i]).abs() < 1e-4);
/// }
/// ```
/// # Unstable
/// This functionality has been recently added in order to find out if the definitions are consistent.
/// However the actual implementation is lacking tests.
/// # Failures
/// VecResult may report the following `ErrorReason` members:
///
/// 1. `VectorMustBeComplex`: if `self` is in real number space.
/// 3. `VectorMetaDataMustAgree`: in case `self` and `function` are not in the same number space and same domain.
pub trait CrossCorrelation<T> : DataVector<T>
    where T : RealNumber {
    type FreqPartner;
    /// Prepares an argument to be used for convolution. Preparing an argument includes two steps:
    ///
    /// 1. Calculate the plain FFT
    /// 2. Calculate the complex conjugate
    fn prepare_argument(self) -> VecResult<Self::FreqPartner>;

    /// Prepares an argument to be used for convolution. The argument is zero padded to length of `2 * self.points() - 1`
    /// and then the same operations are performed as described for `prepare_argument`.
    fn prepare_argument_padded(self) -> VecResult<Self::FreqPartner>;

    /// Calculates the correlation between `self` and `other`. `other` needs to be a time vector which
    /// went through one of the prepare functions `prepare_argument` or `prepare_argument_padded`. See also the
    /// trait description for more details.
    fn correlate(self, other: &Self::FreqPartner) -> VecResult<Self>;
}

macro_rules! define_correlation_impl {
    ($($data_type:ident,$reg:ident);*) => {
        $(
            impl CrossCorrelation<$data_type> for GenericDataVector<$data_type> {
                type FreqPartner = Self;

                fn prepare_argument(self) -> VecResult<Self::FreqPartner> {
                    self.plain_fft()
                    .and_then(|v|v.complex_conj())
                }

                fn prepare_argument_padded(self) -> VecResult<Self::FreqPartner> {
                    let points = self.points();
                    self.zero_pad(2 * points - 1, PaddingOption::Surround)
                    .and_then(|v|v.plain_fft())
                    .and_then(|v|v.complex_conj())
                }

                fn correlate(self, other: &Self::FreqPartner) -> VecResult<Self> {
                    assert_complex!(self);
                    assert_time!(self);
                    let points = other.points();
                    Ok(self)
                    .and_then(|v|v.zero_pad(points, PaddingOption::Surround))
                    .and_then(|v|v.plain_fft())
                    .and_then(|v|v.multiply_vector(&other))
                    .and_then(|v| {
                        let p = v.points();
                        v.real_scale(1.0 / p as $data_type)
                    })
                    .and_then(|v|v.plain_ifft())
                    .and_then(|v|v.swap_halves())
                }
            }
        )*
    }
}
define_correlation_impl!(f32, Reg32; f64, Reg64);

macro_rules! define_correlation_forward {
    ($($name:ident, $data_type:ident);*) => {
        $(
            impl CrossCorrelation<$data_type> for $name<$data_type> {
                type FreqPartner = ComplexFreqVector<$data_type>;
                fn prepare_argument(self) -> VecResult<Self::FreqPartner> {
                    Self::FreqPartner::from_genres(self.to_gen().prepare_argument())
                }

                fn prepare_argument_padded(self) -> VecResult<Self::FreqPartner> {
                    Self::FreqPartner::from_genres(self.to_gen().prepare_argument_padded())
                }

                fn correlate(self, other: &Self::FreqPartner) -> VecResult<Self> {
                    Self::from_genres(self.to_gen().correlate(other.to_gen_borrow()))
                }
            }
        )*
    }
}

define_correlation_forward!(
    ComplexTimeVector, f32; ComplexTimeVector, f64
);

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

    #[test]
    fn time_correlation_test() {
        let a = ComplexTimeVector32::from_interleaved(&[0.0800, 0.0, 0.1876, 0.1170, 0.4601, 0.4132, 0.7700, 0.7500, 0.9723, 0.9698, 0.9723, 0.9698, 0.7700, 0.7500, 0.4601, 0.4132, 0.1876, 0.1170, 0.0800, 0.0]);
        let b = ComplexTimeVector32::from_interleaved(&[0.1000, -0.6366, 0.3000, 0.0, 0.5000, 0.2122, 0.7000, 0.0, 0.9000, -0.1273, 0.9000, 0.0, 0.7000, 0.0909, 0.5000, 0.0, 0.3000, -0.0707, 0.1000, 0.0]);
        let c: &[f32] = &[0.0080, 0.0000, 0.0428, 0.0174, 0.1340, 0.0897, 0.3356, 0.2827, 0.7192, 0.6479, 1.3058, 1.1946, 2.0175, 1.8757,
                          2.7047, 2.5665, 3.2186, 3.0874, 3.4409, 3.2994, 3.2291, 3.1287, 2.5801, 2.7264, 1.7085, 2.1882, 0.8637, 1.6369,
                          0.2319, 1.1420, -0.0878, 0.7078, -0.1208, 0.3523, -0.0317, 0.1311, 0.0080, 0.0509];
        let b = b.prepare_argument_padded().unwrap();
        let res: ComplexTimeVector32 = a.correlate(&b).unwrap();
        let res = res.data();
        let tol = 0.1;
        for i in 0..c.len() {
            if (res[i] - c[i]).abs() > tol {
                panic!("assertion failed: {:?} != {:?} at index {}", res, c, i);
            }
        }
    }

    #[test]
    fn time_correlation_test2() {
        let a = ComplexTimeVector32::from_interleaved(&[1.0, 1.0, 2.0, 1.0, 3.0, 1.0]);
        let b = ComplexTimeVector32::from_interleaved(&[4.0, 1.0, 5.0, 1.0, 6.0, 1.0]);
        let c: &[f32] = &[7.0, 5.0, 19.0, 8.0, 35.0, 9.0, 25.0, 4.0, 13.0, 1.0];
        let b = b.prepare_argument_padded().unwrap();
        let res: ComplexTimeVector32 = a.correlate(&b).unwrap();
        let res = res.data();
        let tol = 0.1;
        for i in 0..c.len() {
            if (res[i] - c[i]).abs() > tol {
                panic!("assertion failed: {:?} != {:?} at index {}", res, c, i);
            }
        }
    }
}<|endoftext|>


<commit_before>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

enum bird {
    pub duck, //~ ERROR: expected identifier, found keyword `pub`
    goose
}

fn main() {
    let y = bird::goose;
}
<commit_msg>Fix test expectations because of #28439<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

enum bird {
    pub duck,
    //~^ ERROR: expected identifier, found keyword `pub`
    //~^^ ERROR: expected
    goose
}

fn main() {
    let y = bird::goose;
}
<|endoftext|>


<commit_before>//! The session that the compositor controls. Each compositor has one session.

use wayland_sys::server::{WAYLAND_SERVER_HANDLE, wl_event_loop,
                          wl_event_loop_timer_func_t};
use wlroots_sys::{self, wl_display, wlr_session, wlr_backend,
                  wlr_session_start, wlr_backend_autocreate, wlr_backend_init};
use std::os::raw::{c_void, c_int};
use std::marker::PhantomData;
use std::any::Any;
use ::Backend;

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum SessionErr {
    SessionFailed,
    DisplayFailed,
    EventLoopFailed,
    BackendFailed
}

/// A session that controls the wl_display, it's event loop, and the
/// [wlr_session](../../wlroots_sys/struct.wlr_session.html)
pub struct Session<'session> {
    /// The backend that this session uses to display content.
    pub backend: Backend,
    /// The session for the compositor. Usually this is via logind.
    pub session: *mut wlr_session,
    /// The pointer to the wayland display proxy object.
    pub display: *mut wl_display,
    /// The pointer to the wayland event loop.
    pub event_loop: *mut wl_event_loop,
    phantom_data: PhantomData<&'session Any>
}

impl <'session> Session<'session> {
    /// Creates a new Wayland session.
    ///
    /// Automatically creates the `wl_display` and `wl_event_loop` objects
    /// using the standard Wayland library.
    pub fn new() -> Result<Self, SessionErr> {
        unsafe {
            let display = ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                                        wl_display_create,) as *mut _;
            if display.is_null() {
                return Err(SessionErr::DisplayFailed)
            }
            let event_loop = ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                                           wl_display_get_event_loop,
                                           display as *mut _);
            if event_loop.is_null() {
                return Err(SessionErr::EventLoopFailed)
            }
            let session = wlr_session_start(display);
            if session.is_null() {
                return Err(SessionErr::SessionFailed)
            }
            let backend = Backend::autocreate_backend(display, session)?;
            Ok(Session {
                backend,
                session,
                display,
                event_loop,
                phantom_data: PhantomData
            })
        }
    }

    /// Dispatches queued events and fetches any new signals/events/requests.
    ///
    /// Returns whatever numerical code `wl_event_loop_dispatch` returns.
    pub fn dispatch_event_loop(&mut self) -> i32 {
        unsafe {
            ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                        wl_event_loop_dispatch,
                        self.event_loop,
                        0)
        }
    }

    pub fn set_timeout<T: Send + Sync, F>(&'session mut self,
                                    data: &'session mut T,
                                    callback: F,
                                    delay: u32) where F: Fn(& mut T) {
        let boxed_func = Box::new(callback);
        let callback_ptr = Box::into_raw(boxed_func);
        let actual_data = Box::new(TimeoutData {
            callback_ptr,
            data
        });
        let actual_data_ptr = Box::into_raw(actual_data);
        unsafe {
            let timer = ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                                    wl_event_loop_add_timer,
                                    self.event_loop,
                                    timer_done::<T, F>,
                                    actual_data_ptr as *mut _);
            if timer.is_null() {
                panic!("Timer was null");
            }
            let res = ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                                    wl_event_source_timer_update,
                                    timer,
                                    delay as i32);
            // TODO Make sure handling this right, return an Err
            if res != 0 {
                panic!("wl_event_loop_add_timer returned an non-zero value!")
            }
        }
    }
}

#[repr(C)]
pub struct TimeoutData<T, F> where F: Fn(&mut T) {
    callback_ptr: *mut F,
    data: *mut T
}

unsafe extern "C" fn timer_done<T, F>(data: *mut c_void) -> c_int
    where F: Fn(&mut T) {
    let data = data as *mut TimeoutData<T, F>;
    let callback = Box::from_raw((*data).callback_ptr);
    let mut real_data = Box::from_raw((*data).data);
    (*callback)(&mut *real_data);
    1
}
<commit_msg>Added TimeoutData and TimeoutDataMut to Session<commit_after>//! The session that the compositor controls. Each compositor has one session.

use wayland_sys::server::{WAYLAND_SERVER_HANDLE, wl_event_loop,
                          wl_event_loop_timer_func_t};
use wlroots_sys::{self, wl_display, wlr_session, wlr_backend,
                  wlr_session_start, wlr_backend_autocreate, wlr_backend_init};
use std::os::raw::{c_void, c_int};
use std::marker::PhantomData;
use std::any::Any;
use ::Backend;

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum SessionErr {
    SessionFailed,
    DisplayFailed,
    EventLoopFailed,
    BackendFailed
}

/// A session that controls the wl_display, it's event loop, and the
/// [wlr_session](../../wlroots_sys/struct.wlr_session.html)
pub struct Session<'session> {
    /// The backend that this session uses to display content.
    pub backend: Backend,
    /// The session for the compositor. Usually this is via logind.
    pub session: *mut wlr_session,
    /// The pointer to the wayland display proxy object.
    pub display: *mut wl_display,
    /// The pointer to the wayland event loop.
    pub event_loop: *mut wl_event_loop,
    phantom_data: PhantomData<&'session Any>
}

impl <'session> Session<'session> {
    /// Creates a new Wayland session.
    ///
    /// Automatically creates the `wl_display` and `wl_event_loop` objects
    /// using the standard Wayland library.
    pub fn new() -> Result<Self, SessionErr> {
        unsafe {
            let display = ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                                        wl_display_create,) as *mut _;
            if display.is_null() {
                return Err(SessionErr::DisplayFailed)
            }
            let event_loop = ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                                           wl_display_get_event_loop,
                                           display as *mut _);
            if event_loop.is_null() {
                return Err(SessionErr::EventLoopFailed)
            }
            let session = wlr_session_start(display);
            if session.is_null() {
                return Err(SessionErr::SessionFailed)
            }
            let backend = Backend::autocreate_backend(display, session)?;
            Ok(Session {
                backend,
                session,
                display,
                event_loop,
                phantom_data: PhantomData
            })
        }
    }

    /// Dispatches queued events and fetches any new signals/events/requests.
    ///
    /// Returns whatever numerical code `wl_event_loop_dispatch` returns.
    pub fn dispatch_event_loop(&mut self) -> i32 {
        unsafe {
            ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                        wl_event_loop_dispatch,
                        self.event_loop,
                        0)
        }
    }

    pub fn set_timeout_mut<'data: 'session, T: Send + Sync + Sized, F>(&mut self, data: &'data mut T, callback: F, delay: u32) where F: Fn(&mut T){
        let actual_data_ptr = TimeoutDataMut::new_raw(data, callback);
        unsafe {
            let timer = ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                                        wl_event_loop_add_timer,
                                        self.event_loop,
                                        timer_done_mut::<T, F>,
                                        actual_data_ptr as *mut _);
            if timer.is_null() {
                panic!("Timer was null");
            }
            let res = ffi_dispatch!(WAYLAND_SERVER_HANDLE, wl_event_source_timer_update,
            timer, delay as i32);
            if res != 0 {
                panic!("wl_event_loop_add_timer returned an non-zero value!")
            }
        }
    }

    pub fn set_timeout<'data: 'session, T: Send + Sync + Sized, F>(&mut self,
                                                           data: &'data T,
                                                           callback: F,
                                                           delay: u32)
        where F: Fn(&T) {
        let actual_data_ptr = TimeoutData::new_raw(data as *const _, callback);
        unsafe {
            let timer = ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                                    wl_event_loop_add_timer,
                                    self.event_loop,
                                    timer_done::<T, F>,
                                    actual_data_ptr as *mut _);
            if timer.is_null() {
                panic!("Timer was null");
            }
            let res = ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                                    wl_event_source_timer_update,
                                    timer,
                                    delay as i32);
            if res != 0 {
                panic!("wl_event_loop_add_timer returned an non-zero value!")
            }
        }
    }
}

#[repr(C)]
pub struct TimeoutData<T: Send + Sync + Sized, F> where F: Fn(&T) {
    callback_ptr: *mut F,
    data: *const T
}

#[repr(C)]
    pub struct TimeoutDataMut<T: Send + Sync + Sized, F> where F: Fn(&mut T) {
    callback_ptr: *mut F,
    data: *mut T
}

impl <T: Send + Sync + Sized, F> TimeoutData<T, F> where F: Fn(&T) {
    /// Create a new TimeoutDataMut allocated on the heap.
    ///
    /// The pointer returned is to be used in C callbacks,
    /// and to be reclaimed later to avoid a leak
    fn new_raw(data: *const T, callback: F) -> *mut Self {
        let boxed_func = Box::new(callback);
        let callback_ptr = Box::into_raw(boxed_func);
        let actual_data = Box::new(TimeoutData {
            callback_ptr,
            data
        });
        Box::into_raw(actual_data)
    }
}

impl <T: Send + Sync + Sized, F> TimeoutDataMut<T, F> where F: Fn(&mut T) {
    /// Create a new TimeoutDataMut allocated on the heap.
    ///
    /// The pointer returned is to be used in C callbacks,
    /// and to be reclaimed later to avoid a leak
    fn new_raw(data: *mut T, callback: F) -> *mut Self {
        let boxed_func = Box::new(callback);
        let callback_ptr = Box::into_raw(boxed_func);
        let actual_data = Box::new(TimeoutDataMut {
            callback_ptr,
            data
        });
        Box::into_raw(actual_data)
    }
}

unsafe extern "C" fn timer_done_mut<T: Send + Sync + Sized, F>(data: *mut c_void) -> c_int
    where F: Fn(&mut T) {
    let data = data as *mut TimeoutDataMut<T, F>;
    let callback = Box::from_raw((*data).callback_ptr as *mut F);
    let mut real_data = Box::from_raw((*data).data as *mut T);
    (*callback)(&mut *real_data);
    1
}

unsafe extern "C" fn timer_done<T: Send + Sync + Sized, F>(data: *mut c_void) -> c_int
    where F: Fn(&T) {
    let data = data as *mut TimeoutData<T, F>;
    let callback = Box::from_raw((*data).callback_ptr as *mut F);
    let real_data = Box::from_raw((*data).data as *mut T);
    (*callback)(&*real_data);
    1
}
<|endoftext|>


<commit_before>use std::fs;
use std::io::prelude::*;
use std::process::Command;
use std::collections::HashMap;
use std::io::BufReader;
use problem::{LpProblem, Problem};
use problem::{LpFileFormat};
use std::fs::File;

#[derive(Debug, PartialEq)]
pub enum Status {
    Optimal,
    SubOptimal,
    Infeasible,
    Unbounded,
    NotSolved,
}

pub trait SolverTrait {
    type P: Problem;
    fn run(&self, problem: &Self::P) -> Result<(Status, HashMap<String,f32>), String>;
}

pub struct GurobiSolver {
    name: String,
    command_name: String,
    temp_solution_file: String,
}
pub struct CbcSolver {
    name: String,
    command_name: String,
    temp_solution_file: String,
}

impl GurobiSolver {
    pub fn new() -> GurobiSolver {
        GurobiSolver { name: "Gurobi".to_string(), command_name: "gurobi_cl".to_string(), temp_solution_file: "sol.sol".to_string() }
    }
    pub fn command_name(&self, command_name: String) -> GurobiSolver {
        GurobiSolver { name: self.name.clone(), command_name: command_name, temp_solution_file: self.temp_solution_file.clone() }
    }
    fn read_solution(&self) -> Result<(Status, HashMap<String, f32>), String> {
        fn read_specific_solution(f: &File) -> Result<(Status, HashMap<String, f32>), String> {

            let mut vars_value: HashMap<_,_> = HashMap::new();
            let mut file = BufReader::new(f);
            let mut buffer = String::new();
            let _ = file.read_line(&mut buffer);

            if let Some(_) = buffer.split(" ").next() {
                for line in file.lines() {
                    let l = line.unwrap();
                    let result_line: Vec<_> = l.split_whitespace().collect();
                    if result_line.len() == 2 {
                        match result_line[1].parse::<f32>() {
                            Ok(n) => {
                                vars_value.insert(result_line[0].to_string(), n);
                            },
                            Err(e) => return Err(format!("{}", e.to_string()))
                        }
                    }else{
                        return Err("Incorrect solution format".to_string())
                    }
                }
            }else{
                return Err("Incorrect solution format".to_string())
            }
            Ok((Status::Optimal, vars_value))
        }

        match File::open(&self.temp_solution_file) {
            Ok(f) => {
                let res = try!(read_specific_solution(&f));
                let _ = fs::remove_file(&self.temp_solution_file);
                Ok(res)
            },
            Err(_) => return Err("Cannot open file".to_string())
        }
    }
}
impl CbcSolver {
    pub fn new() -> CbcSolver {
        CbcSolver { name: "Cbc".to_string(), command_name: "cbc".to_string(), temp_solution_file: "sol.sol".to_string() }
    }
    pub fn command_name(&self, command_name: String) -> CbcSolver {
        CbcSolver { name: self.name.clone(), command_name: command_name, temp_solution_file: self.temp_solution_file.clone() }
    }

    fn read_solution(&self) -> Result<(Status, HashMap<String, f32>), String> {
        fn read_specific_solution(f: &File) -> Result<(Status, HashMap<String, f32>), String> {
            let mut vars_value: HashMap<_, _> = HashMap::new();

            let mut file = BufReader::new(f);
            let mut buffer = String::new();
            let _ = file.read_line(&mut buffer);
            let mut status = Status::SubOptimal;

            if let Some(status_line) = buffer.split(" ").next() {
                if status_line.contains("Optimal") {
                    status = Status::Optimal;
                }
                for line in file.lines() {
                    let l = line.unwrap();
                    let result_line: Vec<_> = l.split_whitespace().collect();
                    if result_line.len() == 4 {
                        match result_line[2].parse::<f32>() {
                            Ok(n) => {
                                vars_value.insert(result_line[1].to_string(), n);
                            },
                            Err(e) => return Err(format!("{}", e.to_string()))
                        }
                    } else {
                        return Err("Incorrect solution format".to_string())
                    }
                }
            } else {
                return Err("Incorrect solution format".to_string())
            }
            Ok((status, vars_value))
        }

        match File::open(&self.temp_solution_file) {
            Ok(f) => {
                let res = try!(read_specific_solution(&f));
                let _ = fs::remove_file(&self.temp_solution_file);
                Ok(res)
            },
            Err(_) => return Err("Cannot open file".to_string())
        }
    }
}

impl SolverTrait for GurobiSolver {
    type P = LpProblem;
    fn run(&self, problem: &Self::P) -> Result<(Status, HashMap<String,f32>), String> {

        let file_model = "test.lp";

        match problem.write_lp(file_model) {
            Ok(_) => {
                match Command::new(&self.command_name).arg(format!("ResultFile={}", self.temp_solution_file)).arg(file_model).output() {
                    Ok(r) => {
                        let mut status = Status::SubOptimal;
                        if String::from_utf8(r.stdout).expect("").contains("Optimal solution found") {
                            status = Status::Optimal;
                        }
                        if r.status.success() {
                            let (_, res) = try!(self.read_solution());
                            Ok((status, res))
                        } else {
                            Err(r.status.to_string())
                        }
                    },
                    Err(_) => Err(format!("Error running the {} solver", self.name)),
                }
            },
            Err(e) => Err(e.to_string()),
        }
    }
}

impl SolverTrait for CbcSolver {
    type P = LpProblem;
    fn run(&self, problem: &Self::P) -> Result<(Status, HashMap<String,f32>), String> {

        let file_model = "test.lp";

        match problem.write_lp(file_model) {
            Ok(_) => {
                match Command::new(&self.command_name).arg(file_model).arg("solve").arg("solution").arg(&self.temp_solution_file).output() {
                    Ok(r) => {
                        if r.status.success(){
                            self.read_solution()
                        }else{
                            Err(r.status.to_string())
                        }
                    },
                    Err(_) => Err(format!("Error running the {} solver", self.name)),
                }
            },
            Err(e) => Err(e.to_string()),
        }
    }
}

<commit_msg>Manage Gurobi v7 comments in header solution file<commit_after>use std::fs;
use std::io::prelude::*;
use std::process::Command;
use std::collections::HashMap;
use std::io::BufReader;
use problem::{LpProblem, Problem};
use problem::{LpFileFormat};
use std::fs::File;

#[derive(Debug, PartialEq)]
pub enum Status {
    Optimal,
    SubOptimal,
    Infeasible,
    Unbounded,
    NotSolved,
}

pub trait SolverTrait {
    type P: Problem;
    fn run(&self, problem: &Self::P) -> Result<(Status, HashMap<String,f32>), String>;
}

pub struct GurobiSolver {
    name: String,
    command_name: String,
    temp_solution_file: String,
}
pub struct CbcSolver {
    name: String,
    command_name: String,
    temp_solution_file: String,
}

impl GurobiSolver {
    pub fn new() -> GurobiSolver {
        GurobiSolver { name: "Gurobi".to_string(), command_name: "gurobi_cl".to_string(), temp_solution_file: "sol.sol".to_string() }
    }
    pub fn command_name(&self, command_name: String) -> GurobiSolver {
        GurobiSolver { name: self.name.clone(), command_name: command_name, temp_solution_file: self.temp_solution_file.clone() }
    }
    fn read_solution(&self) -> Result<(Status, HashMap<String, f32>), String> {
        fn read_specific_solution(f: &File) -> Result<(Status, HashMap<String, f32>), String> {

            let mut vars_value: HashMap<_,_> = HashMap::new();
            let mut file = BufReader::new(f);
            let mut buffer = String::new();
            let _ = file.read_line(&mut buffer);

            if let Some(_) = buffer.split(" ").next() {
                for line in file.lines() {
                    let l = line.unwrap();

                    // Gurobi version 7 add comments on the header file
                    if let Some('#') = l.chars().next() {continue}

                    let result_line: Vec<_> = l.split_whitespace().collect();
                    if result_line.len() == 2 {
                        match result_line[1].parse::<f32>() {
                            Ok(n) => {
                                vars_value.insert(result_line[0].to_string(), n);
                            },
                            Err(e) => return Err(format!("{}", e.to_string()))
                        }
                    } else {
                        return Err("Incorrect solution format".to_string())
                    }
                }
            }else{
                return Err("Incorrect solution format".to_string())
            }
            Ok((Status::Optimal, vars_value))
        }

        match File::open(&self.temp_solution_file) {
            Ok(f) => {
                let res = try!(read_specific_solution(&f));
                let _ = fs::remove_file(&self.temp_solution_file);
                Ok(res)
            },
            Err(_) => return Err("Cannot open file".to_string())
        }
    }
}
impl CbcSolver {
    pub fn new() -> CbcSolver {
        CbcSolver { name: "Cbc".to_string(), command_name: "cbc".to_string(), temp_solution_file: "sol.sol".to_string() }
    }
    pub fn command_name(&self, command_name: String) -> CbcSolver {
        CbcSolver { name: self.name.clone(), command_name: command_name, temp_solution_file: self.temp_solution_file.clone() }
    }

    fn read_solution(&self) -> Result<(Status, HashMap<String, f32>), String> {
        fn read_specific_solution(f: &File) -> Result<(Status, HashMap<String, f32>), String> {
            let mut vars_value: HashMap<_, _> = HashMap::new();

            let mut file = BufReader::new(f);
            let mut buffer = String::new();
            let _ = file.read_line(&mut buffer);
            let mut status = Status::SubOptimal;

            if let Some(status_line) = buffer.split(" ").next() {
                if status_line.contains("Optimal") {
                    status = Status::Optimal;
                }
                for line in file.lines() {
                    let l = line.unwrap();
                    let result_line: Vec<_> = l.split_whitespace().collect();
                    if result_line.len() == 4 {
                        match result_line[2].parse::<f32>() {
                            Ok(n) => {
                                vars_value.insert(result_line[1].to_string(), n);
                            },
                            Err(e) => return Err(format!("{}", e.to_string()))
                        }
                    } else {
                        return Err("Incorrect solution format".to_string())
                    }
                }
            } else {
                return Err("Incorrect solution format".to_string())
            }
            Ok((status, vars_value))
        }

        match File::open(&self.temp_solution_file) {
            Ok(f) => {
                let res = try!(read_specific_solution(&f));
                let _ = fs::remove_file(&self.temp_solution_file);
                Ok(res)
            },
            Err(_) => return Err("Cannot open file".to_string())
        }
    }
}

impl SolverTrait for GurobiSolver {
    type P = LpProblem;
    fn run(&self, problem: &Self::P) -> Result<(Status, HashMap<String,f32>), String> {

        let file_model = "test.lp";

        match problem.write_lp(file_model) {
            Ok(_) => {
                match Command::new(&self.command_name).arg(format!("ResultFile={}", self.temp_solution_file)).arg(file_model).output() {
                    Ok(r) => {
                        let mut status = Status::SubOptimal;
                        if String::from_utf8(r.stdout).expect("").contains("Optimal solution found") {
                            status = Status::Optimal;
                        }
                        if r.status.success() {
                            let (_, res) = try!(self.read_solution());
                            Ok((status, res))
                        } else {
                            Err(r.status.to_string())
                        }
                    },
                    Err(_) => Err(format!("Error running the {} solver", self.name)),
                }
            },
            Err(e) => Err(e.to_string()),
        }
    }
}

impl SolverTrait for CbcSolver {
    type P = LpProblem;
    fn run(&self, problem: &Self::P) -> Result<(Status, HashMap<String,f32>), String> {

        let file_model = "test.lp";

        match problem.write_lp(file_model) {
            Ok(_) => {
                match Command::new(&self.command_name).arg(file_model).arg("solve").arg("solution").arg(&self.temp_solution_file).output() {
                    Ok(r) => {
                        if r.status.success(){
                            self.read_solution()
                        }else{
                            Err(r.status.to_string())
                        }
                    },
                    Err(_) => Err(format!("Error running the {} solver", self.name)),
                }
            },
            Err(e) => Err(e.to_string()),
        }
    }
}

<|endoftext|>