<commit_before>#![allow(dead_code)]
use raft::errors::{Result, Error};
use raft::Storage;
use protobuf::{self, RepeatedField};
use proto::raftpb::{HardState, Entry, EntryType, Message, Snapshot, MessageType, ConfChange,
                    ConfChangeType, ConfState};
use raft::raft::{Config, Raft, SoftState, INVALID_ID};
use raft::Status;
use std::sync::Arc;

#[derive(Debug, Default)]
pub struct Peer {
    pub id: u64,
    pub context: Option<Vec<u8>>,
}

#[derive(Debug, PartialEq, Copy, Clone)]
pub enum SnapshotStatus {
    SnapshotFinish,
    SnapshotFailure,
}

fn is_local_msg(m: &Message) -> bool {
    match m.get_msg_type() {
        MessageType::MsgHup |
        MessageType::MsgBeat |
        MessageType::MsgUnreachable |
        MessageType::MsgSnapStatus |
        MessageType::MsgCheckQuorum => true,
        _ => false,
    }
}

fn is_response_msg(m: &Message) -> bool {
    match m.get_msg_type() {
        MessageType::MsgAppendResponse |
        MessageType::MsgRequestVoteResponse |
        MessageType::MsgHeartbeatResponse |
        MessageType::MsgUnreachable => true,
        _ => false,
    }
}

pub fn is_empty_snap(s: &Snapshot) -> bool {
    s.get_metadata().get_index() == 0
}

// Ready encapsulates the entries and messages that are ready to read,
// be saved to stable storage, committed or sent to other peers.
// All fields in Ready are read-only.
#[derive(Default, Debug, PartialEq)]
pub struct Ready {
    // The current volatile state of a Node.
    // SoftState will be nil if there is no update.
    // It is not required to consume or store SoftState.
    pub ss: Option<SoftState>,

    // The current state of a Node to be saved to stable storage BEFORE
    // Messages are sent.
    // HardState will be equal to empty state if there is no update.
    pub hs: Option<HardState>,

    // Entries specifies entries to be saved to stable storage BEFORE
    // Messages are sent.
    pub entries: Vec<Entry>,

    // Snapshot specifies the snapshot to be saved to stable storage.
    pub snapshot: Snapshot,

    // CommittedEntries specifies entries to be committed to a
    // store/state-machine. These have previously been committed to stable
    // store.
    pub committed_entries: Vec<Entry>,

    // Messages specifies outbound messages to be sent AFTER Entries are
    // committed to stable storage.
    // If it contains a MsgSnap message, the application MUST report back to raft
    // when the snapshot has been received or has failed by calling ReportSnapshot.
    pub messages: Vec<Message>,
}

impl Ready {
    fn new<T: Storage>(raft: &mut Raft<T>, prev_ss: &SoftState, prev_hs: &HardState) -> Ready {
        let mut rd = Ready {
            entries: raft.raft_log.unstable_entries().unwrap_or(&[]).to_vec(),
            committed_entries: raft.raft_log.next_entries().unwrap_or_else(Vec::new),
            messages: raft.msgs.drain(..).collect(),
            ..Default::default()
        };
        let ss = raft.soft_state();
        if &ss != prev_ss {
            rd.ss = Some(ss);
        }
        let hs = raft.hard_state();
        if &hs != prev_hs {
            rd.hs = Some(hs);
        }
        if raft.raft_log.get_unstable().snapshot.is_some() {
            rd.snapshot = raft.raft_log.get_unstable().snapshot.clone().unwrap();
        }
        rd
    }
}

// RawNode is a thread-unsafe Node.
// The methods of this struct correspond to the methods of Node and are described
// more fully there.
pub struct RawNode<T: Storage> {
    pub raft: Raft<T>,
    prev_ss: SoftState,
    prev_hs: HardState,
}

impl<T: Storage> RawNode<T> {
    // NewRawNode returns a new RawNode given configuration and a list of raft peers.
    pub fn new(config: &Config, store: Arc<T>, peers: &[Peer]) -> Result<RawNode<T>> {
        assert!(config.id != 0, "config.id must not be zero");
        let r = Raft::new(config, store);
        let mut rn = RawNode {
            raft: r,
            prev_hs: Default::default(),
            prev_ss: Default::default(),
        };
        let last_index = rn.raft.get_store().last_index().expect("");
        if last_index == 0 {
            rn.raft.become_follower(1, INVALID_ID);
            let mut ents = Vec::with_capacity(peers.len());
            for (i, peer) in peers.iter().enumerate() {
                let mut cc = ConfChange::new();
                cc.set_change_type(ConfChangeType::ConfChangeAddNode);
                cc.set_node_id(peer.id);
                if peer.context.is_some() {
                    cc.set_context(peer.context.as_ref().unwrap().clone());
                }
                let data = protobuf::Message::write_to_bytes(&cc)
                               .expect("unexpected marshal error");
                let mut e = Entry::new();
                e.set_entry_type(EntryType::EntryConfChange);
                e.set_term(1);
                e.set_index(i as u64 + 1);
                e.set_data(data);
                ents.push(e);
            }
            rn.raft.raft_log.append(&ents);
            rn.raft.raft_log.committed = ents.len() as u64;
            for peer in peers {
                rn.raft.add_node(peer.id);
            }
        }
        rn.prev_ss = rn.raft.soft_state();
        rn.prev_hs = rn.raft.hard_state();
        Ok(rn)
    }

    fn commit_ready(&mut self, rd: Ready) {
        if rd.ss.is_some() {
            self.prev_ss = rd.ss.unwrap();
        }
        if let Some(e) = rd.hs {
            if e != HardState::new() {
                self.prev_hs = e;
            }
        }
        if self.prev_hs.get_commit() != 0 {
            // In most cases, prevHardSt and rd.HardState will be the same
            // because when there are new entries to apply we just sent a
            // HardState with an updated Commit value. However, on initial
            // startup the two are different because we don't send a HardState
            // until something changes, but we do send any un-applied but
            // committed entries (and previously-committed entries may be
            // incorporated into the snapshot, even if rd.CommittedEntries is
            // empty). Therefore we mark all committed entries as applied
            // whether they were included in rd.HardState or not.
            self.raft.raft_log.applied_to(self.prev_hs.get_commit());
        }
        if !rd.entries.is_empty() {
            let e = rd.entries.last().unwrap();
            self.raft.raft_log.stable_to(e.get_index(), e.get_term());
        }
        if rd.snapshot != Snapshot::new() {
            self.raft.raft_log.stable_snap_to(rd.snapshot.get_metadata().get_index());
        }
    }

    // Tick advances the internal logical clock by a single tick.
    pub fn tick(&mut self) {
        self.raft.tick();
    }

    // Campaign causes this RawNode to transition to candidate state.
    pub fn campaign(&mut self) -> Result<()> {
        let mut m = Message::new();
        m.set_msg_type(MessageType::MsgHup);
        self.raft.step(m)
    }

    // Propose proposes data be appended to the raft log.
    pub fn propose(&mut self, data: Vec<u8>) -> Result<()> {
        let mut m = Message::new();
        m.set_msg_type(MessageType::MsgPropose);
        m.set_from(self.raft.id);
        let mut e = Entry::new();
        e.set_data(data);
        m.set_entries(RepeatedField::from_vec(vec![e]));
        self.raft.step(m)
    }

    // ProposeConfChange proposes a config change.
    pub fn propose_conf_change(&mut self, cc: ConfChange) -> Result<()> {
        let data = try!(protobuf::Message::write_to_bytes(&cc));
        let mut m = Message::new();
        m.set_msg_type(MessageType::MsgPropose);
        let mut e = Entry::new();
        e.set_entry_type(EntryType::EntryConfChange);
        e.set_data(data);
        m.set_entries(RepeatedField::from_vec(vec![e]));
        self.raft.step(m)
    }

    pub fn apply_conf_change(&mut self, cc: ConfChange) -> ConfState {
        if cc.get_node_id() == INVALID_ID {
            self.raft.reset_pending_conf();
            let mut cs = ConfState::new();
            cs.set_nodes(self.raft.nodes());
            return cs;
        }
        let nid = cc.get_node_id();
        assert!(cc.has_change_type(), "unexpected conf type");
        match cc.get_change_type() {
            ConfChangeType::ConfChangeAddNode => self.raft.add_node(nid),
            ConfChangeType::ConfChangeRemoveNode => self.raft.remove_node(nid),
            ConfChangeType::ConfChangeUpdateNode => self.raft.reset_pending_conf(),
        }
        let mut cs = ConfState::new();
        cs.set_nodes(self.raft.nodes());
        cs
    }

    // Step advances the state machine using the given message.
    pub fn step(&mut self, m: Message) -> Result<()> {
        // ignore unexpected local messages receiving over network
        if is_local_msg(&m) {
            return Err(Error::StepLocalMsg);
        }
        if self.raft.prs.contains_key(&m.get_from()) || is_response_msg(&m) {
            return self.raft.step(m);
        }
        Err(Error::StepPeerNotFound)
    }

    // Ready returns the current point-in-time state of this RawNode.
    pub fn ready(&mut self) -> Ready {
        Ready::new(&mut self.raft, &self.prev_ss, &self.prev_hs)
    }

    // HasReady called when RawNode user need to check if any Ready pending.
    // Checking logic in this method should be consistent with Ready.containsUpdates().
    pub fn has_ready(&self) -> bool {
        let raft = &self.raft;
        if raft.soft_state() != self.prev_ss {
            return true;
        }
        let hs = raft.hard_state();
        if hs != HardState::new() && hs != self.prev_hs {
            return true;
        }
        if Some(true) == raft.raft_log.get_unstable().snapshot.as_ref().map(|s| !is_empty_snap(s)) {
            return true;
        }
        if !raft.msgs.is_empty() || raft.raft_log.unstable_entries().is_some() ||
           raft.raft_log.has_next_entries() {
            return true;
        }
        false
    }

    // Advance notifies the RawNode that the application has applied and saved progress in the
    // last Ready results.
    pub fn advance(&mut self, rd: Ready) {
        self.commit_ready(rd);
    }

    // Status returns the current status of the given group.
    pub fn status(&self) -> Status {
        Status::new(&self.raft)
    }

    // ReportUnreachable reports the given node is not reachable for the last send.
    pub fn report_unreachable(&mut self, id: u64) {
        let mut m = Message::new();
        m.set_msg_type(MessageType::MsgUnreachable);
        m.set_from(id);
        // we don't care if it is ok actually
        self.raft.step(m).is_ok();
    }

    // ReportSnapshot reports the status of the sent snapshot.
    pub fn report_snapshot(&mut self, id: u64, status: SnapshotStatus) {
        let rej = status == SnapshotStatus::SnapshotFailure;
        let mut m = Message::new();
        m.set_msg_type(MessageType::MsgSnapStatus);
        m.set_from(id);
        m.set_reject(rej);
        // we don't care if it is ok actually
        self.raft.step(m).is_ok();
    }
}
<commit_msg>raw_node: fix condition checking.<commit_after>#![allow(dead_code)]
use raft::errors::{Result, Error};
use raft::Storage;
use protobuf::{self, RepeatedField};
use proto::raftpb::{HardState, Entry, EntryType, Message, Snapshot, MessageType, ConfChange,
                    ConfChangeType, ConfState};
use raft::raft::{Config, Raft, SoftState, INVALID_ID};
use raft::Status;
use std::sync::Arc;

#[derive(Debug, Default)]
pub struct Peer {
    pub id: u64,
    pub context: Option<Vec<u8>>,
}

#[derive(Debug, PartialEq, Copy, Clone)]
pub enum SnapshotStatus {
    SnapshotFinish,
    SnapshotFailure,
}

fn is_local_msg(m: &Message) -> bool {
    match m.get_msg_type() {
        MessageType::MsgHup |
        MessageType::MsgBeat |
        MessageType::MsgUnreachable |
        MessageType::MsgSnapStatus |
        MessageType::MsgCheckQuorum => true,
        _ => false,
    }
}

fn is_response_msg(m: &Message) -> bool {
    match m.get_msg_type() {
        MessageType::MsgAppendResponse |
        MessageType::MsgRequestVoteResponse |
        MessageType::MsgHeartbeatResponse |
        MessageType::MsgUnreachable => true,
        _ => false,
    }
}

pub fn is_empty_snap(s: &Snapshot) -> bool {
    s.get_metadata().get_index() == 0
}

// Ready encapsulates the entries and messages that are ready to read,
// be saved to stable storage, committed or sent to other peers.
// All fields in Ready are read-only.
#[derive(Default, Debug, PartialEq)]
pub struct Ready {
    // The current volatile state of a Node.
    // SoftState will be nil if there is no update.
    // It is not required to consume or store SoftState.
    pub ss: Option<SoftState>,

    // The current state of a Node to be saved to stable storage BEFORE
    // Messages are sent.
    // HardState will be equal to empty state if there is no update.
    pub hs: Option<HardState>,

    // Entries specifies entries to be saved to stable storage BEFORE
    // Messages are sent.
    pub entries: Vec<Entry>,

    // Snapshot specifies the snapshot to be saved to stable storage.
    pub snapshot: Snapshot,

    // CommittedEntries specifies entries to be committed to a
    // store/state-machine. These have previously been committed to stable
    // store.
    pub committed_entries: Vec<Entry>,

    // Messages specifies outbound messages to be sent AFTER Entries are
    // committed to stable storage.
    // If it contains a MsgSnap message, the application MUST report back to raft
    // when the snapshot has been received or has failed by calling ReportSnapshot.
    pub messages: Vec<Message>,
}

impl Ready {
    fn new<T: Storage>(raft: &mut Raft<T>, prev_ss: &SoftState, prev_hs: &HardState) -> Ready {
        let mut rd = Ready {
            entries: raft.raft_log.unstable_entries().unwrap_or(&[]).to_vec(),
            committed_entries: raft.raft_log.next_entries().unwrap_or_else(Vec::new),
            messages: raft.msgs.drain(..).collect(),
            ..Default::default()
        };
        let ss = raft.soft_state();
        if &ss != prev_ss {
            rd.ss = Some(ss);
        }
        let hs = raft.hard_state();
        if &hs != prev_hs {
            rd.hs = Some(hs);
        }
        if raft.raft_log.get_unstable().snapshot.is_some() {
            rd.snapshot = raft.raft_log.get_unstable().snapshot.clone().unwrap();
        }
        rd
    }
}

// RawNode is a thread-unsafe Node.
// The methods of this struct correspond to the methods of Node and are described
// more fully there.
pub struct RawNode<T: Storage> {
    pub raft: Raft<T>,
    prev_ss: SoftState,
    prev_hs: HardState,
}

impl<T: Storage> RawNode<T> {
    // NewRawNode returns a new RawNode given configuration and a list of raft peers.
    pub fn new(config: &Config, store: Arc<T>, peers: &[Peer]) -> Result<RawNode<T>> {
        assert!(config.id != 0, "config.id must not be zero");
        let r = Raft::new(config, store);
        let mut rn = RawNode {
            raft: r,
            prev_hs: Default::default(),
            prev_ss: Default::default(),
        };
        let last_index = rn.raft.get_store().last_index().expect("");
        if last_index == 0 {
            rn.raft.become_follower(1, INVALID_ID);
            let mut ents = Vec::with_capacity(peers.len());
            for (i, peer) in peers.iter().enumerate() {
                let mut cc = ConfChange::new();
                cc.set_change_type(ConfChangeType::ConfChangeAddNode);
                cc.set_node_id(peer.id);
                if peer.context.is_some() {
                    cc.set_context(peer.context.as_ref().unwrap().clone());
                }
                let data = protobuf::Message::write_to_bytes(&cc)
                               .expect("unexpected marshal error");
                let mut e = Entry::new();
                e.set_entry_type(EntryType::EntryConfChange);
                e.set_term(1);
                e.set_index(i as u64 + 1);
                e.set_data(data);
                ents.push(e);
            }
            rn.raft.raft_log.append(&ents);
            rn.raft.raft_log.committed = ents.len() as u64;
            for peer in peers {
                rn.raft.add_node(peer.id);
            }
        }
        rn.prev_ss = rn.raft.soft_state();
        rn.prev_hs = rn.raft.hard_state();
        Ok(rn)
    }

    fn commit_ready(&mut self, rd: Ready) {
        if rd.ss.is_some() {
            self.prev_ss = rd.ss.unwrap();
        }
        if let Some(e) = rd.hs {
            if e != HardState::new() {
                self.prev_hs = e;
            }
        }
        if self.prev_hs.get_commit() != 0 {
            // In most cases, prevHardSt and rd.HardState will be the same
            // because when there are new entries to apply we just sent a
            // HardState with an updated Commit value. However, on initial
            // startup the two are different because we don't send a HardState
            // until something changes, but we do send any un-applied but
            // committed entries (and previously-committed entries may be
            // incorporated into the snapshot, even if rd.CommittedEntries is
            // empty). Therefore we mark all committed entries as applied
            // whether they were included in rd.HardState or not.
            self.raft.raft_log.applied_to(self.prev_hs.get_commit());
        }
        if !rd.entries.is_empty() {
            let e = rd.entries.last().unwrap();
            self.raft.raft_log.stable_to(e.get_index(), e.get_term());
        }
        if rd.snapshot != Snapshot::new() {
            self.raft.raft_log.stable_snap_to(rd.snapshot.get_metadata().get_index());
        }
    }

    // Tick advances the internal logical clock by a single tick.
    pub fn tick(&mut self) {
        self.raft.tick();
    }

    // Campaign causes this RawNode to transition to candidate state.
    pub fn campaign(&mut self) -> Result<()> {
        let mut m = Message::new();
        m.set_msg_type(MessageType::MsgHup);
        self.raft.step(m)
    }

    // Propose proposes data be appended to the raft log.
    pub fn propose(&mut self, data: Vec<u8>) -> Result<()> {
        let mut m = Message::new();
        m.set_msg_type(MessageType::MsgPropose);
        m.set_from(self.raft.id);
        let mut e = Entry::new();
        e.set_data(data);
        m.set_entries(RepeatedField::from_vec(vec![e]));
        self.raft.step(m)
    }

    // ProposeConfChange proposes a config change.
    pub fn propose_conf_change(&mut self, cc: ConfChange) -> Result<()> {
        let data = try!(protobuf::Message::write_to_bytes(&cc));
        let mut m = Message::new();
        m.set_msg_type(MessageType::MsgPropose);
        let mut e = Entry::new();
        e.set_entry_type(EntryType::EntryConfChange);
        e.set_data(data);
        m.set_entries(RepeatedField::from_vec(vec![e]));
        self.raft.step(m)
    }

    pub fn apply_conf_change(&mut self, cc: ConfChange) -> ConfState {
        if cc.get_node_id() == INVALID_ID {
            self.raft.reset_pending_conf();
            let mut cs = ConfState::new();
            cs.set_nodes(self.raft.nodes());
            return cs;
        }
        let nid = cc.get_node_id();
        assert!(cc.has_change_type(), "unexpected conf type");
        match cc.get_change_type() {
            ConfChangeType::ConfChangeAddNode => self.raft.add_node(nid),
            ConfChangeType::ConfChangeRemoveNode => self.raft.remove_node(nid),
            ConfChangeType::ConfChangeUpdateNode => self.raft.reset_pending_conf(),
        }
        let mut cs = ConfState::new();
        cs.set_nodes(self.raft.nodes());
        cs
    }

    // Step advances the state machine using the given message.
    pub fn step(&mut self, m: Message) -> Result<()> {
        // ignore unexpected local messages receiving over network
        if is_local_msg(&m) {
            return Err(Error::StepLocalMsg);
        }
        if self.raft.prs.contains_key(&m.get_from()) || !is_response_msg(&m) {
            return self.raft.step(m);
        }
        Err(Error::StepPeerNotFound)
    }

    // Ready returns the current point-in-time state of this RawNode.
    pub fn ready(&mut self) -> Ready {
        Ready::new(&mut self.raft, &self.prev_ss, &self.prev_hs)
    }

    // HasReady called when RawNode user need to check if any Ready pending.
    // Checking logic in this method should be consistent with Ready.containsUpdates().
    pub fn has_ready(&self) -> bool {
        let raft = &self.raft;
        if raft.soft_state() != self.prev_ss {
            return true;
        }
        let hs = raft.hard_state();
        if hs != HardState::new() && hs != self.prev_hs {
            return true;
        }
        if Some(true) == raft.raft_log.get_unstable().snapshot.as_ref().map(|s| !is_empty_snap(s)) {
            return true;
        }
        if !raft.msgs.is_empty() || raft.raft_log.unstable_entries().is_some() ||
           raft.raft_log.has_next_entries() {
            return true;
        }
        false
    }

    // Advance notifies the RawNode that the application has applied and saved progress in the
    // last Ready results.
    pub fn advance(&mut self, rd: Ready) {
        self.commit_ready(rd);
    }

    // Status returns the current status of the given group.
    pub fn status(&self) -> Status {
        Status::new(&self.raft)
    }

    // ReportUnreachable reports the given node is not reachable for the last send.
    pub fn report_unreachable(&mut self, id: u64) {
        let mut m = Message::new();
        m.set_msg_type(MessageType::MsgUnreachable);
        m.set_from(id);
        // we don't care if it is ok actually
        self.raft.step(m).is_ok();
    }

    // ReportSnapshot reports the status of the sent snapshot.
    pub fn report_snapshot(&mut self, id: u64, status: SnapshotStatus) {
        let rej = status == SnapshotStatus::SnapshotFailure;
        let mut m = Message::new();
        m.set_msg_type(MessageType::MsgSnapStatus);
        m.set_from(id);
        m.set_reject(rej);
        // we don't care if it is ok actually
        self.raft.step(m).is_ok();
    }
}
<|endoftext|>


<commit_before>/*!

A render buffer is similar to a texture, but is optimized for usage as a draw target.

Contrary to a texture, you can't sample nor modify the content of a render buffer.
You should prefer render buffers over textures when you know that you don't need to read or modify
the data of the render buffer.

*/
use std::rc::Rc;
use std::mem;

use framebuffer::{ColorAttachment, ToColorAttachment};
use framebuffer::{DepthAttachment, ToDepthAttachment};
use framebuffer::{StencilAttachment, ToStencilAttachment};
use framebuffer::{DepthStencilAttachment, ToDepthStencilAttachment};
use texture::{UncompressedFloatFormat, DepthFormat, StencilFormat, DepthStencilFormat};

use {gl, context};
use {GlObject, DisplayImpl, ToGlEnum};
use ContextExt;
use version::Api;

/// A render buffer is similar to a texture, but is optimized for usage as a draw target.
///
/// Contrary to a texture, you can't sample or modify the content of the `RenderBuffer`.
pub struct RenderBuffer {
    buffer: RenderBufferImpl,
}

impl RenderBuffer {
    /// Builds a new render buffer.
    pub fn new(display: &::Display, format: UncompressedFloatFormat, width: u32, height: u32)
               -> RenderBuffer
    {
        RenderBuffer {
            buffer: RenderBufferImpl::new(display, format.to_glenum(), width, height)
        }
    }

    /// Returns the dimensions of the render buffer.
    pub fn get_dimensions(&self) -> (u32, u32) {
        (self.buffer.width, self.buffer.height)
    }
}

impl ToColorAttachment for RenderBuffer {
    fn to_color_attachment(&self) -> ColorAttachment {
        ColorAttachment::RenderBuffer(self)
    }
}

impl GlObject for RenderBuffer {
    type Id = gl::types::GLuint;
    fn get_id(&self) -> gl::types::GLuint {
        self.buffer.get_id()
    }
}

/// A render buffer is similar to a texture, but is optimized for usage as a draw target.
///
/// Contrary to a texture, you can't sample or modify the content of the `DepthRenderBuffer` directly.
pub struct DepthRenderBuffer {
    buffer: RenderBufferImpl,
}

impl DepthRenderBuffer {
    /// Builds a new render buffer.
    pub fn new(display: &::Display, format: DepthFormat, width: u32, height: u32)
               -> DepthRenderBuffer
    {
        DepthRenderBuffer {
            buffer: RenderBufferImpl::new(display, format.to_glenum(), width, height)
        }
    }

    /// Returns the dimensions of the render buffer.
    pub fn get_dimensions(&self) -> (u32, u32) {
        (self.buffer.width, self.buffer.height)
    }
}

impl ToDepthAttachment for DepthRenderBuffer {
    fn to_depth_attachment(&self) -> DepthAttachment {
        DepthAttachment::RenderBuffer(self)
    }
}

impl GlObject for DepthRenderBuffer {
    type Id = gl::types::GLuint;
    fn get_id(&self) -> gl::types::GLuint {
        self.buffer.get_id()
    }
}

/// A render buffer is similar to a texture, but is optimized for usage as a draw target.
///
/// Contrary to a texture, you can't sample or modify the content of the `StencilRenderBuffer` directly.
pub struct StencilRenderBuffer {
    buffer: RenderBufferImpl,
}

impl StencilRenderBuffer {
    /// Builds a new render buffer.
    pub fn new(display: &::Display, format: StencilFormat, width: u32, height: u32)
               -> StencilRenderBuffer
    {
        StencilRenderBuffer {
            buffer: RenderBufferImpl::new(display, format.to_glenum(), width, height)
        }
    }

    /// Returns the dimensions of the render buffer.
    pub fn get_dimensions(&self) -> (u32, u32) {
        (self.buffer.width, self.buffer.height)
    }
}

impl ToStencilAttachment for StencilRenderBuffer {
    fn to_stencil_attachment(&self) -> StencilAttachment {
        StencilAttachment::RenderBuffer(self)
    }
}

impl GlObject for StencilRenderBuffer {
    type Id = gl::types::GLuint;
    fn get_id(&self) -> gl::types::GLuint {
        self.buffer.get_id()
    }
}

/// A render buffer is similar to a texture, but is optimized for usage as a draw target.
///
/// Contrary to a texture, you can't sample or modify the content of the `DepthStencilRenderBuffer` directly.
pub struct DepthStencilRenderBuffer {
    buffer: RenderBufferImpl,
}

impl DepthStencilRenderBuffer {
    /// Builds a new render buffer.
    pub fn new(display: &::Display, format: DepthStencilFormat, width: u32, height: u32)
               -> DepthStencilRenderBuffer
    {
        DepthStencilRenderBuffer {
            buffer: RenderBufferImpl::new(display, format.to_glenum(), width, height)
        }
    }

    /// Returns the dimensions of the render buffer.
    pub fn get_dimensions(&self) -> (u32, u32) {
        (self.buffer.width, self.buffer.height)
    }
}

impl ToDepthStencilAttachment for DepthStencilRenderBuffer {
    fn to_depth_stencil_attachment(&self) -> DepthStencilAttachment {
        DepthStencilAttachment::RenderBuffer(self)
    }
}

impl GlObject for DepthStencilRenderBuffer {
    type Id = gl::types::GLuint;
    fn get_id(&self) -> gl::types::GLuint {
        self.buffer.get_id()
    }
}

/// The implementation
struct RenderBufferImpl {
    display: Rc<DisplayImpl>,
    id: gl::types::GLuint,
    width: u32,
    height: u32,
}

impl RenderBufferImpl {
    /// Builds a new render buffer.
    fn new(display: &::Display, format: gl::types::GLenum, width: u32, height: u32)
           -> RenderBufferImpl
    {
        // TODO: check that dimensions don't exceed GL_MAX_RENDERBUFFER_SIZE
        let mut ctxt = display.context.context.make_current();

        let id = unsafe {
            let mut id = mem::uninitialized();

            if ctxt.version >= &context::GlVersion(Api::Gl, 4, 5) ||
                ctxt.extensions.gl_arb_direct_state_access
            {
                ctxt.gl.CreateRenderbuffers(1, &mut id);
                ctxt.gl.NamedRenderbufferStorage(id, format, width as gl::types::GLsizei,
                                                 height as gl::types::GLsizei);

            } else if ctxt.version >= &context::GlVersion(Api::Gl, 3, 0) ||
                      ctxt.version >= &context::GlVersion(Api::GlEs, 2, 0)
            {
                ctxt.gl.GenRenderbuffers(1, &mut id);
                ctxt.gl.BindRenderbuffer(gl::RENDERBUFFER, id);
                ctxt.state.renderbuffer = id;
                // FIXME: gles2 only supports very few formats
                ctxt.gl.RenderbufferStorage(gl::RENDERBUFFER, format,
                                            width as gl::types::GLsizei,
                                            height as gl::types::GLsizei);

            } else if ctxt.extensions.gl_ext_framebuffer_object {
                ctxt.gl.GenRenderbuffersEXT(1, &mut id);
                ctxt.gl.BindRenderbufferEXT(gl::RENDERBUFFER_EXT, id);
                ctxt.state.renderbuffer = id;
                ctxt.gl.RenderbufferStorageEXT(gl::RENDERBUFFER_EXT, format,
                                               width as gl::types::GLsizei,
                                               height as gl::types::GLsizei);

            } else {
                unreachable!();
            }

            id
        };

        RenderBufferImpl {
            display: display.context.clone(),
            id: id,
            width: width,
            height: height,
        }
    }
}

impl Drop for RenderBufferImpl {
    fn drop(&mut self) {
        unsafe {
            let mut ctxt = self.display.context.make_current();

            // removing FBOs which contain this buffer
            self.display.context.framebuffer_objects.as_ref().unwrap()
                        .purge_renderbuffer(self.id, &mut ctxt);

            if ctxt.version >= &context::GlVersion(Api::Gl, 3, 0) ||
               ctxt.version >= &context::GlVersion(Api::GlEs, 2, 0)
            {
                if ctxt.state.renderbuffer == self.id {
                    ctxt.gl.BindRenderbuffer(gl::RENDERBUFFER, 0);
                    ctxt.state.renderbuffer = 0;
                }
                ctxt.gl.DeleteRenderbuffers(1, [ self.id ].as_ptr());

            } else if ctxt.extensions.gl_ext_framebuffer_object {
                if ctxt.state.renderbuffer == self.id {
                    ctxt.gl.BindRenderbufferEXT(gl::RENDERBUFFER_EXT, 0);
                    ctxt.state.renderbuffer = 0;
                }
                ctxt.gl.DeleteRenderbuffersEXT(1, [ self.id ].as_ptr());

            } else {
                unreachable!();
            }
        }
    }
}

impl GlObject for RenderBufferImpl {
    type Id = gl::types::GLuint;
    fn get_id(&self) -> gl::types::GLuint {
        self.id
    }
}
<commit_msg>Fix render_buffer.rs for facade change<commit_after>/*!

A render buffer is similar to a texture, but is optimized for usage as a draw target.

Contrary to a texture, you can't sample nor modify the content of a render buffer.
You should prefer render buffers over textures when you know that you don't need to read or modify
the data of the render buffer.

*/
use std::rc::Rc;
use std::mem;

use framebuffer::{ColorAttachment, ToColorAttachment};
use framebuffer::{DepthAttachment, ToDepthAttachment};
use framebuffer::{StencilAttachment, ToStencilAttachment};
use framebuffer::{DepthStencilAttachment, ToDepthStencilAttachment};
use texture::{UncompressedFloatFormat, DepthFormat, StencilFormat, DepthStencilFormat};

use {gl, context};
use {GlObject, ToGlEnum};
use backend::Facade;
use context::Context;
use ContextExt;
use version::Api;

/// A render buffer is similar to a texture, but is optimized for usage as a draw target.
///
/// Contrary to a texture, you can't sample or modify the content of the `RenderBuffer`.
pub struct RenderBuffer {
    buffer: RenderBufferImpl,
}

impl RenderBuffer {
    /// Builds a new render buffer.
    pub fn new<F>(facade: &F, format: UncompressedFloatFormat, width: u32, height: u32)
                  -> RenderBuffer where F: Facade
    {
        RenderBuffer {
            buffer: RenderBufferImpl::new(facade, format.to_glenum(), width, height)
        }
    }

    /// Returns the dimensions of the render buffer.
    pub fn get_dimensions(&self) -> (u32, u32) {
        (self.buffer.width, self.buffer.height)
    }
}

impl ToColorAttachment for RenderBuffer {
    fn to_color_attachment(&self) -> ColorAttachment {
        ColorAttachment::RenderBuffer(self)
    }
}

impl GlObject for RenderBuffer {
    type Id = gl::types::GLuint;
    fn get_id(&self) -> gl::types::GLuint {
        self.buffer.get_id()
    }
}

/// A render buffer is similar to a texture, but is optimized for usage as a draw target.
///
/// Contrary to a texture, you can't sample or modify the content of the `DepthRenderBuffer` directly.
pub struct DepthRenderBuffer {
    buffer: RenderBufferImpl,
}

impl DepthRenderBuffer {
    /// Builds a new render buffer.
    pub fn new<F>(facade: &F, format: DepthFormat, width: u32, height: u32)
                  -> DepthRenderBuffer where F: Facade
    {
        DepthRenderBuffer {
            buffer: RenderBufferImpl::new(facade, format.to_glenum(), width, height)
        }
    }

    /// Returns the dimensions of the render buffer.
    pub fn get_dimensions(&self) -> (u32, u32) {
        (self.buffer.width, self.buffer.height)
    }
}

impl ToDepthAttachment for DepthRenderBuffer {
    fn to_depth_attachment(&self) -> DepthAttachment {
        DepthAttachment::RenderBuffer(self)
    }
}

impl GlObject for DepthRenderBuffer {
    type Id = gl::types::GLuint;
    fn get_id(&self) -> gl::types::GLuint {
        self.buffer.get_id()
    }
}

/// A render buffer is similar to a texture, but is optimized for usage as a draw target.
///
/// Contrary to a texture, you can't sample or modify the content of the `StencilRenderBuffer` directly.
pub struct StencilRenderBuffer {
    buffer: RenderBufferImpl,
}

impl StencilRenderBuffer {
    /// Builds a new render buffer.
    pub fn new<F>(facade: &F, format: StencilFormat, width: u32, height: u32)
                  -> StencilRenderBuffer where F: Facade
    {
        StencilRenderBuffer {
            buffer: RenderBufferImpl::new(facade, format.to_glenum(), width, height)
        }
    }

    /// Returns the dimensions of the render buffer.
    pub fn get_dimensions(&self) -> (u32, u32) {
        (self.buffer.width, self.buffer.height)
    }
}

impl ToStencilAttachment for StencilRenderBuffer {
    fn to_stencil_attachment(&self) -> StencilAttachment {
        StencilAttachment::RenderBuffer(self)
    }
}

impl GlObject for StencilRenderBuffer {
    type Id = gl::types::GLuint;
    fn get_id(&self) -> gl::types::GLuint {
        self.buffer.get_id()
    }
}

/// A render buffer is similar to a texture, but is optimized for usage as a draw target.
///
/// Contrary to a texture, you can't sample or modify the content of the `DepthStencilRenderBuffer` directly.
pub struct DepthStencilRenderBuffer {
    buffer: RenderBufferImpl,
}

impl DepthStencilRenderBuffer {
    /// Builds a new render buffer.
    pub fn new<F>(facade: &F, format: DepthStencilFormat, width: u32, height: u32)
                  -> DepthStencilRenderBuffer where F: Facade
    {
        DepthStencilRenderBuffer {
            buffer: RenderBufferImpl::new(facade, format.to_glenum(), width, height)
        }
    }

    /// Returns the dimensions of the render buffer.
    pub fn get_dimensions(&self) -> (u32, u32) {
        (self.buffer.width, self.buffer.height)
    }
}

impl ToDepthStencilAttachment for DepthStencilRenderBuffer {
    fn to_depth_stencil_attachment(&self) -> DepthStencilAttachment {
        DepthStencilAttachment::RenderBuffer(self)
    }
}

impl GlObject for DepthStencilRenderBuffer {
    type Id = gl::types::GLuint;
    fn get_id(&self) -> gl::types::GLuint {
        self.buffer.get_id()
    }
}

/// The implementation
struct RenderBufferImpl {
    context: Rc<Context>,
    id: gl::types::GLuint,
    width: u32,
    height: u32,
}

impl RenderBufferImpl {
    /// Builds a new render buffer.
    fn new<F>(facade: &F, format: gl::types::GLenum, width: u32, height: u32)
              -> RenderBufferImpl where F: Facade
    {
        // TODO: check that dimensions don't exceed GL_MAX_RENDERBUFFER_SIZE
        let mut ctxt = facade.get_context().make_current();

        let id = unsafe {
            let mut id = mem::uninitialized();

            if ctxt.version >= &context::GlVersion(Api::Gl, 4, 5) ||
                ctxt.extensions.gl_arb_direct_state_access
            {
                ctxt.gl.CreateRenderbuffers(1, &mut id);
                ctxt.gl.NamedRenderbufferStorage(id, format, width as gl::types::GLsizei,
                                                 height as gl::types::GLsizei);

            } else if ctxt.version >= &context::GlVersion(Api::Gl, 3, 0) ||
                      ctxt.version >= &context::GlVersion(Api::GlEs, 2, 0)
            {
                ctxt.gl.GenRenderbuffers(1, &mut id);
                ctxt.gl.BindRenderbuffer(gl::RENDERBUFFER, id);
                ctxt.state.renderbuffer = id;
                // FIXME: gles2 only supports very few formats
                ctxt.gl.RenderbufferStorage(gl::RENDERBUFFER, format,
                                            width as gl::types::GLsizei,
                                            height as gl::types::GLsizei);

            } else if ctxt.extensions.gl_ext_framebuffer_object {
                ctxt.gl.GenRenderbuffersEXT(1, &mut id);
                ctxt.gl.BindRenderbufferEXT(gl::RENDERBUFFER_EXT, id);
                ctxt.state.renderbuffer = id;
                ctxt.gl.RenderbufferStorageEXT(gl::RENDERBUFFER_EXT, format,
                                               width as gl::types::GLsizei,
                                               height as gl::types::GLsizei);

            } else {
                unreachable!();
            }

            id
        };

        RenderBufferImpl {
            context: facade.get_context().clone(),
            id: id,
            width: width,
            height: height,
        }
    }
}

impl Drop for RenderBufferImpl {
    fn drop(&mut self) {
        unsafe {
            let mut ctxt = self.context.make_current();

            // removing FBOs which contain this buffer
            self.context.framebuffer_objects.as_ref().unwrap()
                        .purge_renderbuffer(self.id, &mut ctxt);

            if ctxt.version >= &context::GlVersion(Api::Gl, 3, 0) ||
               ctxt.version >= &context::GlVersion(Api::GlEs, 2, 0)
            {
                if ctxt.state.renderbuffer == self.id {
                    ctxt.gl.BindRenderbuffer(gl::RENDERBUFFER, 0);
                    ctxt.state.renderbuffer = 0;
                }
                ctxt.gl.DeleteRenderbuffers(1, [ self.id ].as_ptr());

            } else if ctxt.extensions.gl_ext_framebuffer_object {
                if ctxt.state.renderbuffer == self.id {
                    ctxt.gl.BindRenderbufferEXT(gl::RENDERBUFFER_EXT, 0);
                    ctxt.state.renderbuffer = 0;
                }
                ctxt.gl.DeleteRenderbuffersEXT(1, [ self.id ].as_ptr());

            } else {
                unreachable!();
            }
        }
    }
}

impl GlObject for RenderBufferImpl {
    type Id = gl::types::GLuint;
    fn get_id(&self) -> gl::types::GLuint {
        self.id
    }
}
<|endoftext|>


<commit_before>extern crate allergies;

use allergies::*;

fn compare_allergy_vectors(expected: &Vec<Allergen>, actual: &Vec<Allergen>) {
    for element in expected {
        if !actual.contains(element) {
            panic!("Allergen missing\n  {:?} should be in {:?}",
                   element,
                   actual);
        }
    }

    if actual.len() != expected.len() {
        panic!("Allergy vectors are of different lengths\n  expected {:?}\n  got {:?}",
               expected,
               actual);
    }
}

#[test]
fn is_not_allergic_to_anything() {
    let allergies = Allergies::new(0);
    assert_eq!(false, allergies.is_allergic_to(&Allergen::Peanuts));
    assert_eq!(false, allergies.is_allergic_to(&Allergen::Cats));
    assert_eq!(false, allergies.is_allergic_to(&Allergen::Strawberries));
}

#[test]
#[ignore]
fn is_allergic_to_eggs() {
    assert_eq!(true, Allergies::new(1).is_allergic_to(&Allergen::Eggs));
}

#[test]
#[ignore]
fn is_allergic_to_egg_shellfish_and_strawberries() {
    let allergies = Allergies::new(5);
    assert_eq!(true, allergies.is_allergic_to(&Allergen::Eggs));
    assert_eq!(true, allergies.is_allergic_to(&Allergen::Shellfish));
    assert_eq!(false, allergies.is_allergic_to(&Allergen::Strawberries));
}

#[test]
#[ignore]
fn no_allergies_at_all() {
    let expected: Vec<Allergen> = Vec::new();
    let allergies = Allergies::new(0).allergies();

    compare_allergy_vectors(&expected, &allergies);
}

#[test]
#[ignore]
fn allergic_to_just_eggs() {
    let expected = vec![Allergen::Eggs];
    let allergies = Allergies::new(1).allergies();

    compare_allergy_vectors(&expected, &allergies);
}

#[test]
#[ignore]
fn allergic_to_just_peanuts() {
    let expected = vec![Allergen::Peanuts];
    let allergies = Allergies::new(2).allergies();

    compare_allergy_vectors(&expected, &allergies);
}

#[test]
#[ignore]
fn allergic_to_just_strawberries() {
    let expected = vec![Allergen::Strawberries];
    let allergies = Allergies::new(8).allergies();

    compare_allergy_vectors(&expected, &allergies);
}

#[test]
#[ignore]
fn allergic_to_eggs_and_peanuts() {
    let expected = vec![Allergen::Eggs, Allergen::Peanuts];
    let allergies = Allergies::new(3).allergies();

    compare_allergy_vectors(&expected, &allergies);
}

#[test]
#[ignore]
fn allergic_to_eggs_and_shellfish() {
    let expected = vec![Allergen::Eggs, Allergen::Shellfish];
    let allergies = Allergies::new(5).allergies();

    compare_allergy_vectors(&expected, &allergies);
}

#[test]
#[ignore]
fn allergic_to_many_things() {
    let expected = vec![Allergen::Strawberries,
                        Allergen::Tomatoes,
                        Allergen::Chocolate,
                        Allergen::Pollen,
                        Allergen::Cats];
    let allergies = Allergies::new(248).allergies();

    compare_allergy_vectors(&expected, &allergies);
}

#[test]
#[ignore]
fn allergic_to_everything() {
    let expected = vec![Allergen::Eggs,
                        Allergen::Peanuts,
                        Allergen::Shellfish,
                        Allergen::Strawberries,
                        Allergen::Tomatoes,
                        Allergen::Chocolate,
                        Allergen::Pollen,
                        Allergen::Cats];
    let allergies = Allergies::new(255).allergies();

    compare_allergy_vectors(&expected, &allergies);
}

#[test]
#[ignore]
fn scores_over_255_do_not_trigger_false_positives() {
    let expected = vec![Allergen::Eggs,
                        Allergen::Shellfish,
                        Allergen::Strawberries,
                        Allergen::Tomatoes,
                        Allergen::Chocolate,
                        Allergen::Pollen,
                        Allergen::Cats];
    let allergies = Allergies::new(509).allergies();

    compare_allergy_vectors(&expected, &allergies);
}
<commit_msg>allergies: Use &[T] instead of &Vec<T> for signatures<commit_after>extern crate allergies;

use allergies::*;

fn compare_allergy_vectors(expected: &[Allergen], actual: &[Allergen]) {
    for element in expected {
        if !actual.contains(element) {
            panic!("Allergen missing\n  {:?} should be in {:?}",
                   element,
                   actual);
        }
    }

    if actual.len() != expected.len() {
        panic!("Allergy vectors are of different lengths\n  expected {:?}\n  got {:?}",
               expected,
               actual);
    }
}

#[test]
fn is_not_allergic_to_anything() {
    let allergies = Allergies::new(0);
    assert_eq!(false, allergies.is_allergic_to(&Allergen::Peanuts));
    assert_eq!(false, allergies.is_allergic_to(&Allergen::Cats));
    assert_eq!(false, allergies.is_allergic_to(&Allergen::Strawberries));
}

#[test]
#[ignore]
fn is_allergic_to_eggs() {
    assert_eq!(true, Allergies::new(1).is_allergic_to(&Allergen::Eggs));
}

#[test]
#[ignore]
fn is_allergic_to_egg_shellfish_and_strawberries() {
    let allergies = Allergies::new(5);
    assert_eq!(true, allergies.is_allergic_to(&Allergen::Eggs));
    assert_eq!(true, allergies.is_allergic_to(&Allergen::Shellfish));
    assert_eq!(false, allergies.is_allergic_to(&Allergen::Strawberries));
}

#[test]
#[ignore]
fn no_allergies_at_all() {
    let expected: Vec<Allergen> = Vec::new();
    let allergies = Allergies::new(0).allergies();

    compare_allergy_vectors(&expected, &allergies);
}

#[test]
#[ignore]
fn allergic_to_just_eggs() {
    let expected = vec![Allergen::Eggs];
    let allergies = Allergies::new(1).allergies();

    compare_allergy_vectors(&expected, &allergies);
}

#[test]
#[ignore]
fn allergic_to_just_peanuts() {
    let expected = vec![Allergen::Peanuts];
    let allergies = Allergies::new(2).allergies();

    compare_allergy_vectors(&expected, &allergies);
}

#[test]
#[ignore]
fn allergic_to_just_strawberries() {
    let expected = vec![Allergen::Strawberries];
    let allergies = Allergies::new(8).allergies();

    compare_allergy_vectors(&expected, &allergies);
}

#[test]
#[ignore]
fn allergic_to_eggs_and_peanuts() {
    let expected = vec![Allergen::Eggs, Allergen::Peanuts];
    let allergies = Allergies::new(3).allergies();

    compare_allergy_vectors(&expected, &allergies);
}

#[test]
#[ignore]
fn allergic_to_eggs_and_shellfish() {
    let expected = vec![Allergen::Eggs, Allergen::Shellfish];
    let allergies = Allergies::new(5).allergies();

    compare_allergy_vectors(&expected, &allergies);
}

#[test]
#[ignore]
fn allergic_to_many_things() {
    let expected = vec![Allergen::Strawberries,
                        Allergen::Tomatoes,
                        Allergen::Chocolate,
                        Allergen::Pollen,
                        Allergen::Cats];
    let allergies = Allergies::new(248).allergies();

    compare_allergy_vectors(&expected, &allergies);
}

#[test]
#[ignore]
fn allergic_to_everything() {
    let expected = vec![Allergen::Eggs,
                        Allergen::Peanuts,
                        Allergen::Shellfish,
                        Allergen::Strawberries,
                        Allergen::Tomatoes,
                        Allergen::Chocolate,
                        Allergen::Pollen,
                        Allergen::Cats];
    let allergies = Allergies::new(255).allergies();

    compare_allergy_vectors(&expected, &allergies);
}

#[test]
#[ignore]
fn scores_over_255_do_not_trigger_false_positives() {
    let expected = vec![Allergen::Eggs,
                        Allergen::Shellfish,
                        Allergen::Strawberries,
                        Allergen::Tomatoes,
                        Allergen::Chocolate,
                        Allergen::Pollen,
                        Allergen::Cats];
    let allergies = Allergies::new(509).allergies();

    compare_allergy_vectors(&expected, &allergies);
}
<|endoftext|>


<commit_before>#![feature(phase, macro_rules, if_let)]

extern crate serialize;
extern crate libc;
#[phase(plugin, link)] extern crate log;
extern crate regex;
#[phase(plugin)] extern crate regex_macros;
extern crate time;
extern crate debug;

extern crate argparse;
extern crate quire;
#[phase(plugin, link)] extern crate lithos;

use std::io::stderr;
use std::io::IoError;
use std::io::ALL_PERMISSIONS;
use std::os::{set_exit_status, self_exe_path};
use std::path::BytesContainer;
use std::from_str::FromStr;
use std::io::fs::{copy, rmdir_recursive, mkdir, readdir, rename};
use std::io::fs::{readlink, symlink, File};
use std::io::fs::PathExtensions;
use std::default::Default;
use std::io::process::{Command, InheritFd, ExitStatus};

use argparse::{ArgumentParser, Store, StoreOption, StoreTrue};
use quire::parse_config;

use lithos::master_config::MasterConfig;
use lithos::tree_config::TreeConfig;
use lithos::container_config::ContainerConfig;
use lithos::child_config::ChildConfig;
use lithos::signal;
use lithos::sha256::{Sha256,Digest};

fn copy_dir(source: &Path, target: &Path) -> Result<(), IoError> {
    let name_re = regex!(r"^([\w-]+)\.yaml$");
    let mut tmpdir = Path::new(target.dirname())
        .join(b".tmp.".to_vec() + target.filename().unwrap());
    if tmpdir.exists() {
        try!(rmdir_recursive(&tmpdir));
    }
    try!(mkdir(&tmpdir, ALL_PERMISSIONS));
    for file in try!(readdir(source))
        .into_iter()
        .filter(|f| f.filename_str()
                     .map(|s| name_re.is_match(s))
                     .unwrap_or(false))
    {
        try!(copy(&file, &tmpdir.join(file.filename().unwrap())));
    }
    try!(rename(&tmpdir, target));
    return Ok(());
}

fn hash_dir(dir: &Path) -> Result<String, IoError> {
    let name_re = regex!(r"^([\w-]+)\.yaml$");
    let mut hash = Sha256::new();
    let mut files: Vec<Path> = try!(readdir(dir))
        .into_iter()
        .filter(|f| f.filename_str()
                     .map(|s| name_re.is_match(s))
                     .unwrap_or(false))
        .collect();
    files.sort();
    for file in files.iter() {
        hash.input(file.container_as_bytes());
        hash.input(b"\x00");
        hash.input(try!(try!(File::open(file)).read_to_end()).as_slice());
        hash.input(b"\x00");
    }
    return Ok(hash.result_str().as_slice().slice_to(8).to_string());
}

fn switch_config(master_cfg: Path, tree_name: String, config_dir: Path,
    name_prefix: Option<String>)
    -> Result<(), String>
{
    match Command::new(self_exe_path().unwrap().join("lithos_check"))
        .stdin(InheritFd(0))
        .stdout(InheritFd(1))
        .stderr(InheritFd(2))
        .arg("--config")
        .arg(&master_cfg)
        .arg("--tree")
        .arg(tree_name.as_slice())
        .arg("--config-dir")
        .arg(&config_dir)
        .output()
    {
        Ok(ref po) if po.status == ExitStatus(0) => { }
        Ok(ref po) => {
            return Err(format!(
                "Configuration check failed with exit status: {}",
                po.status));
        }
        Err(e) => {
            return Err(format!("Can't check configuration: {}", e));
        }
    }
    info!("Checked. Proceeding");

    let master: MasterConfig = match parse_config(&master_cfg,
        &*MasterConfig::validator(), Default::default())
    {
        Ok(cfg) => cfg,
        Err(e) => {
            return Err(format!("Can't parse master config: {}", e));
        }
    };
    let tree_fn = master.config_dir.join(tree_name + ".yaml");
    let tree: TreeConfig = match parse_config(&tree_fn,
        &*TreeConfig::validator(), Default::default())
    {
        Ok(cfg) => cfg,
        Err(e) => {
            return Err(format!("Can't parse tree config: {}", e));
        }
    };

    let config_fn = if let Some(prefix) = name_prefix {
        prefix.to_string() + try!(hash_dir(&config_dir)
            .map_err(|e| format!("Can't read dir: {}", e)))
    } else {
        config_dir.filename_str().unwrap().to_string()
    };
    let target_fn = Path::new(tree.config_dir.dirname())
                    .join(config_fn.as_slice());
    if target_fn == tree.config_dir {
        return Err(format!(concat!(
            "Target config dir ({}) is the current dir ({}). ",
            "You must have unique name for each new configuration"),
            target_fn.display(), tree.config_dir.display()));
    }
    let lnk = readlink(&tree.config_dir);
    match lnk.as_ref().map(|f| f.dirname()) {
        Ok(b".") => {},
        _ => return Err(format!(concat!(
            "The path {} must be a directory which points to the directory ",
            "at the same level of hierarchy."), tree.config_dir.display())),
    };
    if lnk.unwrap().filename() == target_fn.filename() {
        warn!("Target config dir is the active one. Nothing to do.");
        return Ok(());
    }
    if target_fn.exists() {
        warn!(concat!("Target directory {} exists. ",
            "Probably already copied. Skipping copying step."),
            target_fn.display());
    } else {
        info!("Seems everything nice. Copying");
        match copy_dir(&config_dir, &target_fn) {
            Ok(()) => {}
            Err(e) => return Err(format!("Error copying config dir: {}", e)),
        }
    }
    info!("Ok files are there. Making symlink");
    let symlink_fn = tree.config_dir.with_filename(
        b".tmp.".to_vec() + tree.config_dir.filename().unwrap());
    try!(symlink(&Path::new(config_fn.as_slice()), &symlink_fn)
        .map_err(|e| format!("Error symlinking dir: {}", e)));
    try!(rename(&symlink_fn, &tree.config_dir)
        .map_err(|e| format!("Error replacing symlink: {}", e)));

    info!("Done. Sending SIGQUIT to lithos_tree");
    let pid_file = master.runtime_dir.join("master.pid");
    let pid = match File::open(&pid_file)
            .and_then(|mut f| f.read_to_string())
            .ok()
            .and_then(|s| FromStr::from_str(s.as_slice())) {
        Some(pid) if signal::is_process_alive(pid) => {
            signal::send_signal(pid, signal::SIGQUIT as int);
        }
        Some(pid) => {
            warn!("Process with pid {} is not running...", pid);
        }
        None => {
            warn!("Can't read pid file {}. Probably daemon is not running.",
                pid_file.display());
        }
    };

    return Ok(());
}

fn main() {
    let mut master_config = Path::new("/etc/lithos.yaml");
    let mut verbose = false;
    let mut name_prefix = None;
    let mut config_dir = Path::new("");
    let mut tree_name = "".to_string();
    {
        let mut ap = ArgumentParser::new();
        ap.set_description("Checks if lithos configuration is ok");
        ap.refer(&mut master_config)
          .add_option(["--master"], box Store::<Path>,
            "Name of the master configuration file (default /etc/lithos.yaml)")
          .metavar("FILE");
        ap.refer(&mut verbose)
          .add_option(["-v", "--verbose"], box StoreTrue,
            "Verbose configuration");
        ap.refer(&mut name_prefix)
          .add_option(["--hashed-name"], box StoreOption::<String>, "
            Do not last component of DIR as a name, but create an unique name
            based on the PREFIX and hash of the contents.
            ")
          .metavar("PREFIX");
        ap.refer(&mut tree_name)
          .add_argument("tree", box Store::<String>,
            "Name of the tree which configuration will be switched for")
          .required()
          .metavar("NAME");
        ap.refer(&mut config_dir)
          .add_argument("dir", box Store::<Path>, "
            Name of the configuration directory to switch to. It doesn't
            have to be a directory inside `config-dir`, and it will be copied
            there. However, if directory with the same name exists in the
            `config-dir` it's assumed that it's already copied and will not
            be updated. Be sure to use unique directory for each deployment.
            ")
          .required();
        match ap.parse_args() {
            Ok(()) => {}
            Err(x) => {
                set_exit_status(x);
                return;
            }
        }
    }
    match switch_config(master_config, tree_name, config_dir, name_prefix) {
        Ok(()) => {
            set_exit_status(0);
        }
        Err(e) => {
            (write!(stderr(), "Fatal error: {}\n", e)).ok();
            set_exit_status(1);
        }
    }
}
<commit_msg>Removed warnings in lithos_switch<commit_after>#![feature(phase, macro_rules, if_let)]

extern crate serialize;
extern crate libc;
#[phase(plugin, link)] extern crate log;
extern crate regex;
#[phase(plugin)] extern crate regex_macros;
extern crate time;
extern crate debug;

extern crate argparse;
extern crate quire;
#[phase(plugin, link)] extern crate lithos;

use std::io::stderr;
use std::io::IoError;
use std::io::ALL_PERMISSIONS;
use std::os::{set_exit_status, self_exe_path};
use std::path::BytesContainer;
use std::from_str::FromStr;
use std::io::fs::{copy, rmdir_recursive, mkdir, readdir, rename};
use std::io::fs::{readlink, symlink, File};
use std::io::fs::PathExtensions;
use std::default::Default;
use std::io::process::{Command, InheritFd, ExitStatus};

use argparse::{ArgumentParser, Store, StoreOption, StoreTrue};
use quire::parse_config;

use lithos::master_config::MasterConfig;
use lithos::tree_config::TreeConfig;
use lithos::signal;
use lithos::sha256::{Sha256,Digest};

fn copy_dir(source: &Path, target: &Path) -> Result<(), IoError> {
    let name_re = regex!(r"^([\w-]+)\.yaml$");
    let tmpdir = Path::new(target.dirname())
        .join(b".tmp.".to_vec() + target.filename().unwrap());
    if tmpdir.exists() {
        try!(rmdir_recursive(&tmpdir));
    }
    try!(mkdir(&tmpdir, ALL_PERMISSIONS));
    for file in try!(readdir(source))
        .into_iter()
        .filter(|f| f.filename_str()
                     .map(|s| name_re.is_match(s))
                     .unwrap_or(false))
    {
        try!(copy(&file, &tmpdir.join(file.filename().unwrap())));
    }
    try!(rename(&tmpdir, target));
    return Ok(());
}

fn hash_dir(dir: &Path) -> Result<String, IoError> {
    let name_re = regex!(r"^([\w-]+)\.yaml$");
    let mut hash = Sha256::new();
    let mut files: Vec<Path> = try!(readdir(dir))
        .into_iter()
        .filter(|f| f.filename_str()
                     .map(|s| name_re.is_match(s))
                     .unwrap_or(false))
        .collect();
    files.sort();
    for file in files.iter() {
        hash.input(file.container_as_bytes());
        hash.input(b"\x00");
        hash.input(try!(try!(File::open(file)).read_to_end()).as_slice());
        hash.input(b"\x00");
    }
    return Ok(hash.result_str().as_slice().slice_to(8).to_string());
}

fn switch_config(master_cfg: Path, tree_name: String, config_dir: Path,
    name_prefix: Option<String>)
    -> Result<(), String>
{
    match Command::new(self_exe_path().unwrap().join("lithos_check"))
        .stdin(InheritFd(0))
        .stdout(InheritFd(1))
        .stderr(InheritFd(2))
        .arg("--config")
        .arg(&master_cfg)
        .arg("--tree")
        .arg(tree_name.as_slice())
        .arg("--config-dir")
        .arg(&config_dir)
        .output()
    {
        Ok(ref po) if po.status == ExitStatus(0) => { }
        Ok(ref po) => {
            return Err(format!(
                "Configuration check failed with exit status: {}",
                po.status));
        }
        Err(e) => {
            return Err(format!("Can't check configuration: {}", e));
        }
    }
    info!("Checked. Proceeding");

    let master: MasterConfig = match parse_config(&master_cfg,
        &*MasterConfig::validator(), Default::default())
    {
        Ok(cfg) => cfg,
        Err(e) => {
            return Err(format!("Can't parse master config: {}", e));
        }
    };
    let tree_fn = master.config_dir.join(tree_name + ".yaml");
    let tree: TreeConfig = match parse_config(&tree_fn,
        &*TreeConfig::validator(), Default::default())
    {
        Ok(cfg) => cfg,
        Err(e) => {
            return Err(format!("Can't parse tree config: {}", e));
        }
    };

    let config_fn = if let Some(prefix) = name_prefix {
        prefix.to_string() + try!(hash_dir(&config_dir)
            .map_err(|e| format!("Can't read dir: {}", e)))
    } else {
        config_dir.filename_str().unwrap().to_string()
    };
    let target_fn = Path::new(tree.config_dir.dirname())
                    .join(config_fn.as_slice());
    if target_fn == tree.config_dir {
        return Err(format!(concat!(
            "Target config dir ({}) is the current dir ({}). ",
            "You must have unique name for each new configuration"),
            target_fn.display(), tree.config_dir.display()));
    }
    let lnk = readlink(&tree.config_dir);
    match lnk.as_ref().map(|f| f.dirname()) {
        Ok(b".") => {},
        _ => return Err(format!(concat!(
            "The path {} must be a directory which points to the directory ",
            "at the same level of hierarchy."), tree.config_dir.display())),
    };
    if lnk.unwrap().filename() == target_fn.filename() {
        warn!("Target config dir is the active one. Nothing to do.");
        return Ok(());
    }
    if target_fn.exists() {
        warn!(concat!("Target directory {} exists. ",
            "Probably already copied. Skipping copying step."),
            target_fn.display());
    } else {
        info!("Seems everything nice. Copying");
        match copy_dir(&config_dir, &target_fn) {
            Ok(()) => {}
            Err(e) => return Err(format!("Error copying config dir: {}", e)),
        }
    }
    info!("Ok files are there. Making symlink");
    let symlink_fn = tree.config_dir.with_filename(
        b".tmp.".to_vec() + tree.config_dir.filename().unwrap());
    try!(symlink(&Path::new(config_fn.as_slice()), &symlink_fn)
        .map_err(|e| format!("Error symlinking dir: {}", e)));
    try!(rename(&symlink_fn, &tree.config_dir)
        .map_err(|e| format!("Error replacing symlink: {}", e)));

    info!("Done. Sending SIGQUIT to lithos_tree");
    let pid_file = master.runtime_dir.join("master.pid");
    match File::open(&pid_file)
            .and_then(|mut f| f.read_to_string())
            .ok()
            .and_then(|s| FromStr::from_str(s.as_slice())) {
        Some(pid) if signal::is_process_alive(pid) => {
            signal::send_signal(pid, signal::SIGQUIT as int);
        }
        Some(pid) => {
            warn!("Process with pid {} is not running...", pid);
        }
        None => {
            warn!("Can't read pid file {}. Probably daemon is not running.",
                pid_file.display());
        }
    };

    return Ok(());
}

fn main() {
    let mut master_config = Path::new("/etc/lithos.yaml");
    let mut verbose = false;
    let mut name_prefix = None;
    let mut config_dir = Path::new("");
    let mut tree_name = "".to_string();
    {
        let mut ap = ArgumentParser::new();
        ap.set_description("Checks if lithos configuration is ok");
        ap.refer(&mut master_config)
          .add_option(["--master"], box Store::<Path>,
            "Name of the master configuration file (default /etc/lithos.yaml)")
          .metavar("FILE");
        ap.refer(&mut verbose)
          .add_option(["-v", "--verbose"], box StoreTrue,
            "Verbose configuration");
        ap.refer(&mut name_prefix)
          .add_option(["--hashed-name"], box StoreOption::<String>, "
            Do not last component of DIR as a name, but create an unique name
            based on the PREFIX and hash of the contents.
            ")
          .metavar("PREFIX");
        ap.refer(&mut tree_name)
          .add_argument("tree", box Store::<String>,
            "Name of the tree which configuration will be switched for")
          .required()
          .metavar("NAME");
        ap.refer(&mut config_dir)
          .add_argument("dir", box Store::<Path>, "
            Name of the configuration directory to switch to. It doesn't
            have to be a directory inside `config-dir`, and it will be copied
            there. However, if directory with the same name exists in the
            `config-dir` it's assumed that it's already copied and will not
            be updated. Be sure to use unique directory for each deployment.
            ")
          .required();
        match ap.parse_args() {
            Ok(()) => {}
            Err(x) => {
                set_exit_status(x);
                return;
            }
        }
    }
    match switch_config(master_config, tree_name, config_dir, name_prefix) {
        Ok(()) => {
            set_exit_status(0);
        }
        Err(e) => {
            (write!(stderr(), "Fatal error: {}\n", e)).ok();
            set_exit_status(1);
        }
    }
}
<|endoftext|>


<commit_before>//! Draws text on the screen using the turtle.
//!
//! This example draws the text introduced as a first parameter
//! for example:
//!   cargo run --example letters 'Wow! So cool!'
//! Draw the text 'Wow! So cool!'
//! the optional second parameter is a font size, for example:
//!   cargo run --example letters 'Big text!' 50
//! Draw the text 'Big text!' with font size 50
//! if you don't insert any parameter:
//!   cargo run --example letters
//! this will draw a simple "hello, world!"

use std::env;
use std::process;

mod a_to_d;
mod diacritics;
mod e_to_i;
mod j_to_o;
mod numbers;
mod p_to_t;
mod punctuation;
mod u_to_z;

use a_to_d::*;
use diacritics::*;
use e_to_i::*;
use j_to_o::*;
use numbers::*;
use p_to_t::*;
use punctuation::*;
use u_to_z::*;

use turtle::Turtle;

fn main() {
    let mut turtle = Turtle::new();
    turtle.set_speed("fast");

    let (text, font_size) = parse_args();

    // Go to the start of the text
    go_to_initial_position(&mut turtle, &text, font_size);

    for character in text.chars() {
        match character {
            '0' => zero(&mut turtle, font_size),
            '1' => one(&mut turtle, font_size),
            '2' => two(&mut turtle, font_size),
            '3' => three(&mut turtle, font_size),
            '4' => four(&mut turtle, font_size),
            '5' => five(&mut turtle, font_size),
            '6' => six(&mut turtle, font_size),
            '7' => seven(&mut turtle, font_size),
            '8' => eight(&mut turtle, font_size),
            '9' => nine(&mut turtle, font_size),
            'a' | 'A' => a(&mut turtle, font_size),
            'b' | 'B' => b(&mut turtle, font_size),
            'c' | 'C' => c(&mut turtle, font_size),
            'd' | 'D' => d(&mut turtle, font_size),
            'e' | 'E' => e(&mut turtle, font_size),
            'f' | 'F' => f(&mut turtle, font_size),
            'g' | 'G' => g(&mut turtle, font_size),
            'h' | 'H' => h(&mut turtle, font_size),
            'i' | 'I' => i(&mut turtle, font_size),
            'j' | 'J' => j(&mut turtle, font_size),
            'k' | 'K' => k(&mut turtle, font_size),
            'l' | 'L' => l(&mut turtle, font_size),
            'm' | 'M' => m(&mut turtle, font_size),
            'n' | 'N' => n(&mut turtle, font_size),
            'ñ' | 'Ñ' => {
                tilde(&mut turtle, font_size);
                turtle.pen_up();
                turtle.left(90.0);
                turtle.forward(1.5 * font_size);
                turtle.right(90.0);
                turtle.pen_down();
                n(&mut turtle, font_size);
            }
            'o' | 'O' => o(&mut turtle, font_size),
            'p' | 'P' => p(&mut turtle, font_size),
            'q' | 'Q' => q(&mut turtle, font_size),
            'r' | 'R' => r(&mut turtle, font_size),
            's' | 'S' => s(&mut turtle, font_size),
            't' | 'T' => t(&mut turtle, font_size),
            'u' | 'U' => u(&mut turtle, font_size),
            'v' | 'V' => v(&mut turtle, font_size),
            'w' | 'W' => w(&mut turtle, font_size),
            'x' | 'X' => x(&mut turtle, font_size),
            'y' | 'Y' => y(&mut turtle, font_size),
            'z' | 'Z' => z(&mut turtle, font_size),
            'á' | 'Á' | 'é' | 'É' | 'í' | 'Í' | 'ó' | 'Ó' | 'ú' | 'Ú' => {
                acutte(&mut turtle, font_size);
                turtle.left(90.0);
                turtle.forward(font_size);
                turtle.pen_down();
                turtle.right(90.0);
                match character {
                    'á' | 'Á' => a(&mut turtle, font_size),
                    'é' | 'É' => e(&mut turtle, font_size),
                    'í' | 'Í' => i(&mut turtle, font_size),
                    'ó' | 'Ó' => o(&mut turtle, font_size),
                    _ => u(&mut turtle, font_size),
                };
            }
            '´' => acutte(&mut turtle, font_size),
            '\'' => apostrophe(&mut turtle, font_size),
            ':' => colon(&mut turtle, font_size),
            ',' => comma(&mut turtle, font_size),
            '.' => dot(&mut turtle, font_size),
            '!' => exclamation(&mut turtle, font_size),
            '¡' => inverted_exclamation(&mut turtle, font_size),
            '¿' => inverted_question(&mut turtle, font_size),
            '?' => question(&mut turtle, font_size),
            ';' => semicolon(&mut turtle, font_size),
            '~' => tilde(&mut turtle, font_size),
            character if character.is_whitespace() => space(&mut turtle, font_size),
            _ => {
                println!("We still don't have an implementation for the '{}' character!", character);
                println!("but you can add it!:");
                println!("https://github.com/sunjay/turtle#contributing");
                question(&mut turtle, font_size);
            }
        }
        turtle.pen_down();
    }
    turtle.hide();
}

fn go_to_initial_position(turtle: &mut Turtle, text: &str, font_size: f64) {
    turtle.pen_up();
    turtle.left(90.0);
    for _ in text.chars() {
        turtle.forward(font_size / 2.0);
    }
    turtle.right(90.0);
    turtle.pen_down();
}

/// Parses the command line arguments or exits with a help message if there was
/// an error
fn parse_args() -> (String, f64) {
    let mut args = env::args();

    // Skip the first argument (the executable name)
    args.next();

    // First argument is the text to draw
    let text = match args.next() {
        Some(text) if text == "--help" => print_help(),

        // This can produce any text, including the empty string
        Some(text) => text,
        // Default to `Hello, World!`
        None => "Hello, World!".to_string(),
    };

    // Second argument is the font size
    let font_size: f64 = match args.next() {
        Some(text) if text == "--help" => print_help(),

        Some(font_size) => match font_size.parse() {
            Ok(font_size) => {
                if font_size >= 1.0 {
                    font_size
                } else {
                    println!("Font size argument must be at least 1.0");
                    println!();
                    print_help();
                }
            }

            Err(err) => {
                println!("Font size argument must be a valid number: {}", err);
                println!();
                print_help();
            }
        },

        // Default to a font size of 20
        None => 20.0,
    };

    // Not expecting any other arguments
    if args.next().is_some() {
        print_help()
    }

    (text, font_size)
}

/// Prints the help message and then exits
///
/// `!` is the "never type" and it means this function never returns
fn print_help() -> ! {
    println!("Draws text on the screen using the turtle.");
    println!();
    println!("EXAMPLES:");
    println!("  cargo run --example letters 'Wow! So cool!'");
    println!("    Draw the text 'Wow! So cool!'");
    println!();
    println!("  cargo run --example letters 'Big text!' 50");
    println!("    Draw the text 'Big text!' with font size 50");
    println!();
    println!("  cargo run --example letters -- --help");
    println!("    Show this help information");
    println!();
    println!("FLAGS:");
    println!("  --help  show this help information");

    process::exit(0)
}
<commit_msg>Tech Debt: less impl details in the match statment<commit_after>//! Draws text on the screen using the turtle.
//!
//! This example draws the text introduced as a first parameter
//! for example:
//!   cargo run --example letters 'Wow! So cool!'
//! Draw the text 'Wow! So cool!'
//! the optional second parameter is a font size, for example:
//!   cargo run --example letters 'Big text!' 50
//! Draw the text 'Big text!' with font size 50
//! if you don't insert any parameter:
//!   cargo run --example letters
//! this will draw a simple "hello, world!"

use std::env;
use std::process;

mod a_to_d;
mod diacritics;
mod e_to_i;
mod j_to_o;
mod numbers;
mod p_to_t;
mod punctuation;
mod u_to_z;

use a_to_d::*;
use diacritics::*;
use e_to_i::*;
use j_to_o::*;
use numbers::*;
use p_to_t::*;
use punctuation::*;
use u_to_z::*;

use turtle::Turtle;

fn main() {
    let mut turtle = Turtle::new();
    turtle.set_speed("fast");

    let (text, font_size) = parse_args();

    // Go to the start of the text
    go_to_initial_position(&mut turtle, &text, font_size);

    for character in text.chars() {
        match character {
            '0' => zero(&mut turtle, font_size),
            '1' => one(&mut turtle, font_size),
            '2' => two(&mut turtle, font_size),
            '3' => three(&mut turtle, font_size),
            '4' => four(&mut turtle, font_size),
            '5' => five(&mut turtle, font_size),
            '6' => six(&mut turtle, font_size),
            '7' => seven(&mut turtle, font_size),
            '8' => eight(&mut turtle, font_size),
            '9' => nine(&mut turtle, font_size),
            'a' | 'A' => a(&mut turtle, font_size),
            'b' | 'B' => b(&mut turtle, font_size),
            'c' | 'C' => c(&mut turtle, font_size),
            'd' | 'D' => d(&mut turtle, font_size),
            'e' | 'E' => e(&mut turtle, font_size),
            'f' | 'F' => f(&mut turtle, font_size),
            'g' | 'G' => g(&mut turtle, font_size),
            'h' | 'H' => h(&mut turtle, font_size),
            'i' | 'I' => i(&mut turtle, font_size),
            'j' | 'J' => j(&mut turtle, font_size),
            'k' | 'K' => k(&mut turtle, font_size),
            'l' | 'L' => l(&mut turtle, font_size),
            'm' | 'M' => m(&mut turtle, font_size),
            'n' | 'N' => n(&mut turtle, font_size),
            'ñ' | 'Ñ' => {
                tilde(&mut turtle, font_size);
                with_title(&mut turtle, font_size);
                n(&mut turtle, font_size);
            }
            'o' | 'O' => o(&mut turtle, font_size),
            'p' | 'P' => p(&mut turtle, font_size),
            'q' | 'Q' => q(&mut turtle, font_size),
            'r' | 'R' => r(&mut turtle, font_size),
            's' | 'S' => s(&mut turtle, font_size),
            't' | 'T' => t(&mut turtle, font_size),
            'u' | 'U' => u(&mut turtle, font_size),
            'v' | 'V' => v(&mut turtle, font_size),
            'w' | 'W' => w(&mut turtle, font_size),
            'x' | 'X' => x(&mut turtle, font_size),
            'y' | 'Y' => y(&mut turtle, font_size),
            'z' | 'Z' => z(&mut turtle, font_size),
            'á' | 'Á' | 'é' | 'É' | 'í' | 'Í' | 'ó' | 'Ó' | 'ú' | 'Ú' => {
                acutte(&mut turtle, font_size);
                with_accute(&mut turtle, font_size);
                match character {
                    'á' | 'Á' => a(&mut turtle, font_size),
                    'é' | 'É' => e(&mut turtle, font_size),
                    'í' | 'Í' => i(&mut turtle, font_size),
                    'ó' | 'Ó' => o(&mut turtle, font_size),
                    _ => u(&mut turtle, font_size),
                };
            }
            '´' => acutte(&mut turtle, font_size),
            '\'' => apostrophe(&mut turtle, font_size),
            ':' => colon(&mut turtle, font_size),
            ',' => comma(&mut turtle, font_size),
            '.' => dot(&mut turtle, font_size),
            '!' => exclamation(&mut turtle, font_size),
            '¡' => inverted_exclamation(&mut turtle, font_size),
            '¿' => inverted_question(&mut turtle, font_size),
            '?' => question(&mut turtle, font_size),
            ';' => semicolon(&mut turtle, font_size),
            '~' => tilde(&mut turtle, font_size),
            character if character.is_whitespace() => space(&mut turtle, font_size),
            _ => {
                println!("We still don't have an implementation for the '{}' character!", character);
                println!("but you can add it!:");
                println!("https://github.com/sunjay/turtle#contributing");
                question(&mut turtle, font_size);
            }
        }
        turtle.pen_down();
    }
    turtle.hide();
}

fn go_to_initial_position(turtle: &mut Turtle, text: &str, font_size: f64) {
    turtle.pen_up();
    turtle.left(90.0);
    for _ in text.chars() {
        turtle.forward(font_size / 2.0);
    }
    turtle.right(90.0);
    turtle.pen_down();
}

fn with_title(turtle: &mut Turtle, font_size: f64) {
    turtle.pen_up();
    turtle.left(90.0);
    turtle.forward(1.5 * font_size);
    turtle.right(90.0);
    turtle.pen_down();
}

fn with_accute(turtle: &mut Turtle, font_size: f64) {
    turtle.left(90.0);
    turtle.forward(font_size);
    turtle.pen_down();
    turtle.right(90.0);
}

/// Parses the command line arguments or exits with a help message if there was
/// an error
fn parse_args() -> (String, f64) {
    let mut args = env::args();

    // Skip the first argument (the executable name)
    args.next();

    // First argument is the text to draw
    let text = match args.next() {
        Some(text) if text == "--help" => print_help(),

        // This can produce any text, including the empty string
        Some(text) => text,
        // Default to `Hello, World!`
        None => "Hello, World!".to_string(),
    };

    // Second argument is the font size
    let font_size: f64 = match args.next() {
        Some(text) if text == "--help" => print_help(),

        Some(font_size) => match font_size.parse() {
            Ok(font_size) => {
                if font_size >= 1.0 {
                    font_size
                } else {
                    println!("Font size argument must be at least 1.0");
                    println!();
                    print_help();
                }
            }

            Err(err) => {
                println!("Font size argument must be a valid number: {}", err);
                println!();
                print_help();
            }
        },

        // Default to a font size of 20
        None => 20.0,
    };

    // Not expecting any other arguments
    if args.next().is_some() {
        print_help()
    }

    (text, font_size)
}

/// Prints the help message and then exits
///
/// `!` is the "never type" and it means this function never returns
fn print_help() -> ! {
    println!("Draws text on the screen using the turtle.");
    println!();
    println!("EXAMPLES:");
    println!("  cargo run --example letters 'Wow! So cool!'");
    println!("    Draw the text 'Wow! So cool!'");
    println!();
    println!("  cargo run --example letters 'Big text!' 50");
    println!("    Draw the text 'Big text!' with font size 50");
    println!();
    println!("  cargo run --example letters -- --help");
    println!("    Show this help information");
    println!();
    println!("FLAGS:");
    println!("  --help  show this help information");

    process::exit(0)
}
<|endoftext|>


<commit_before><commit_msg>kill the workers if the master did not find the command socket<commit_after><|endoftext|>