<commit_before>//! Matrix rooms.

use std::collections::{HashMap, HashSet};
use std::convert::{TryFrom, TryInto};

use diesel::{Connection, ExecuteDsl, ExpressionMethods, FilterDsl, FindDsl, LoadDsl, OrderDsl, insert};
use diesel::pg::PgConnection;
use diesel::pg::data_types::PgTimestamp;
use diesel::pg::expression::dsl::any;
use diesel::result::Error as DieselError;
use ruma_events::EventType;
use ruma_events::room::create::{CreateEvent, CreateEventContent};
use ruma_events::room::history_visibility::{
    HistoryVisibility,
    HistoryVisibilityEvent,
    HistoryVisibilityEventContent,
};
use ruma_events::room::join_rules::{
    JoinRule,
    JoinRulesEvent,
    JoinRulesEventContent,
};
use ruma_events::room::name::{NameEvent, NameEventContent};
use ruma_events::room::power_levels::{PowerLevelsEvent, PowerLevelsEventContent};
use ruma_events::room::topic::{TopicEvent, TopicEventContent};
use ruma_identifiers::{EventId, RoomAliasId, RoomId, UserId};

use error::ApiError;
use models::event::{Event, NewEvent};
use models::room_alias::{NewRoomAlias, RoomAlias};
use models::room_membership::{RoomMembership, RoomMembershipOptions};
use models::user::User;
use schema::{events, rooms, users};

/// Options provided by the user to customize the room upon creation.
pub struct CreationOptions {
    /// An initial alias for the room.
    pub alias: Option<String>,
    /// Whether or not the room should be federated.
    pub federate: bool,
    /// A list of users to invite to the room.
    pub invite_list: Option<Vec<String>>,
    /// An initial name for the room.
    pub name: Option<String>,
    /// A convenience parameter for setting a few default state events.
    pub preset: RoomPreset,
    /// An initial topic for the room.
    pub topic: Option<String>,
}

/// A new Matrix room, not yet saved.
#[derive(Debug, Insertable)]
#[table_name = "rooms"]
pub struct NewRoom {
    /// The room's unique ID.
    pub id: RoomId,
    /// The ID of the user creating the room.
    pub user_id: UserId,
    /// Whether or not the room is visible in the directory.
    pub public: bool,
}

/// A Matrix room.
#[derive(Debug, Queryable)]
pub struct Room {
    /// The room's unique ID.
    pub id: RoomId,
    /// The ID of the user who created the room.
    pub user_id: UserId,
    /// Whether or not the room is visible in the directory.
    pub public: bool,
    /// The time the room was created.
    pub created_at: PgTimestamp,
}

/// A convenience parameter for setting a few default state events.
#[derive(Clone, Copy, Debug, Deserialize)]
pub enum RoomPreset {
    /// `join_rules` is set to `invite` and `history_visibility` is set to `shared`.
    PrivateChat,
    /// `join_rules` is set to `public` and `history_visibility` is set to `shared`.
    PublicChat,
    /// Same as `PrivateChat`, but all initial invitees get the same power level as the creator.
    TrustedPrivateChat,
}

impl Room {
    /// Creates a new room in the database.
    pub fn create(
        connection: &PgConnection,
        new_room: &NewRoom,
        homeserver_domain: &str,
        creation_options: &CreationOptions,
    ) -> Result<Room, ApiError> {
        connection.transaction::<Room, ApiError, _>(|| {
            let room: Room = insert(new_room)
                .into(rooms::table)
                .get_result(connection)
                .map_err(ApiError::from)?;

            if let Some(ref alias) = creation_options.alias {
                let new_room_alias = NewRoomAlias {
                    alias: RoomAliasId::try_from(&format!("#{}:{}", alias, homeserver_domain))?,
                    room_id: room.id.clone(),
                    user_id: new_room.user_id.clone(),
                    servers: vec![homeserver_domain.to_string()],
                };

                RoomAlias::create(connection, homeserver_domain, &new_room_alias)?;
            }

            let mut new_events = Vec::new();

            let new_create_event: NewEvent = CreateEvent {
                content: CreateEventContent {
                    creator: new_room.user_id.clone(),
                    federate: creation_options.federate,
                },
                event_id: EventId::new(homeserver_domain)?,
                event_type: EventType::RoomCreate,
                prev_content: None,
                room_id: room.id.clone(),
                state_key: "".to_string(),
                unsigned: None,
                user_id: new_room.user_id.clone(),
            }.try_into()?;

            new_events.push(new_create_event);

            if let Some(ref name) = creation_options.name {
                let new_name_event: NewEvent = NameEvent {
                    content: NameEventContent {
                        name: name.to_string(),
                    },
                    event_id: EventId::new(homeserver_domain)?,
                    event_type: EventType::RoomName,
                    prev_content: None,
                    room_id: room.id.clone(),
                    state_key: "".to_string(),
                    unsigned: None,
                    user_id: new_room.user_id.clone(),
                }.try_into()?;

                new_events.push(new_name_event);
            }

            if let Some(ref topic) = creation_options.topic {
                let new_topic_event: NewEvent = TopicEvent {
                    content: TopicEventContent {
                        topic: topic.to_string(),
                    },
                    event_id: EventId::new(homeserver_domain)?,
                    event_type: EventType::RoomTopic,
                    prev_content: None,
                    room_id: room.id.clone(),
                    state_key: "".to_string(),
                    unsigned: None,
                    user_id: new_room.user_id.clone(),
                }.try_into()?;

                new_events.push(new_topic_event);
            }

            let new_history_visibility_event: NewEvent = HistoryVisibilityEvent {
                content: HistoryVisibilityEventContent {
                    history_visibility: HistoryVisibility::Shared,
                },
                event_id: EventId::new(homeserver_domain)?,
                event_type: EventType::RoomHistoryVisibility,
                prev_content: None,
                room_id: room.id.clone(),
                state_key: "".to_string(),
                unsigned: None,
                user_id: new_room.user_id.clone(),
            }.try_into()?;

            new_events.push(new_history_visibility_event);

            match creation_options.preset {
                RoomPreset::PrivateChat => {
                    let new_join_rules_event: NewEvent = JoinRulesEvent {
                        content: JoinRulesEventContent { join_rule: JoinRule::Invite },
                        event_id: EventId::new(homeserver_domain)?,
                        event_type: EventType::RoomJoinRules,
                        prev_content: None,
                        room_id: room.id.clone(),
                        state_key: "".to_string(),
                        unsigned: None,
                        user_id: new_room.user_id.clone(),
                    }.try_into()?;

                    new_events.push(new_join_rules_event);
                }
                RoomPreset::PublicChat => {
                    let new_join_rules_event: NewEvent = JoinRulesEvent {
                        content: JoinRulesEventContent { join_rule: JoinRule::Public },
                        event_id: EventId::new(homeserver_domain)?,
                        event_type: EventType::RoomJoinRules,
                        prev_content: None,
                        room_id: room.id.clone(),
                        state_key: "".to_string(),
                        unsigned: None,
                        user_id: new_room.user_id.clone(),
                    }.try_into()?;

                    new_events.push(new_join_rules_event);
                }
                RoomPreset::TrustedPrivateChat => {
                    let new_join_rules_event: NewEvent = JoinRulesEvent {
                        content: JoinRulesEventContent { join_rule: JoinRule::Invite },
                        event_id: EventId::new(homeserver_domain)?,
                        event_type: EventType::RoomJoinRules,
                        prev_content: None,
                        room_id: room.id.clone(),
                        state_key: "".to_string(),
                        unsigned: None,
                        user_id: new_room.user_id.clone(),
                    }.try_into()?;

                    new_events.push(new_join_rules_event);
                }
            }

            insert(&new_events)
                .into(events::table)
                .execute(connection)
                .map_err(ApiError::from)?;

            if let Some(ref invite_list) = creation_options.invite_list {
                room.create_memberships(connection, &invite_list, homeserver_domain)?;
            }

            Ok(room)
        }).map_err(ApiError::from)
    }

    /// Looks up the most recent power levels event for the room.
    ///
    /// If the room does not have a power levels event, a default one is created according to the
    /// specification.
    pub fn current_power_levels(&self, connection: &PgConnection)
    -> Result<PowerLevelsEventContent, ApiError> {
        match events::table
            .filter(events::room_id.eq(self.id.clone()))
            .filter(events::event_type.eq(EventType::RoomPowerLevels.to_string()))
            .order(events::ordering.desc())
            .first::<Event>(connection)
        {
            Ok(event) => {
                let power_levels_event: PowerLevelsEvent = event.try_into()?;

                Ok(power_levels_event.content)
            }
            Err(error) => match error {
                DieselError::NotFound => Ok(PowerLevelsEventContent {
                    ban: 50,
                    events: HashMap::new(),
                    events_default: 0,
                    invite: 50,
                    kick: 50,
                    redact: 50,
                    state_default: 0,
                    users: HashMap::new(),
                    users_default: 0,
                }),
                _ => Err(error.into()),
            },
        }
    }

    /// Look up a `Room` given the `RoomId`.
    pub fn find(connection: &PgConnection, room_id: &RoomId)
    -> Result<Room, ApiError> {
        rooms::table
            .find(room_id)
            .get_result(connection)
            .map(Room::from)
            .map_err(|err| {
                match err {
                    DieselError::NotFound => ApiError::not_found(
                        "The room was not found on this server".to_string()
                    ),
                    _ => ApiError::from(err)
                }
            })
    }

    /// Given a list of invited users create the appropriate `m.room.member` events.
    fn create_memberships(&self, connection: &PgConnection, invite_list: &Vec<String>, homeserver_domain: &str)
    -> Result<(), ApiError> {
        let mut user_ids = HashSet::with_capacity(invite_list.len());

        for invitee in invite_list {
            let user_id = UserId::try_from(invitee)?;

            if user_id.hostname().to_string() != homeserver_domain {
                return Err(
                    ApiError::unimplemented("Federation is not yet supported.".to_string())
                );
            }

            user_ids.insert(user_id);
        }

        let users: Vec<User> = users::table
            .filter(users::id.eq(any(
                user_ids.iter().cloned().collect::<Vec<UserId>>()))
            )
            .get_results(connection)
            .map_err(ApiError::from)?;

        let loaded_user_ids: HashSet<UserId> = users
            .iter()
            .map(|user| user.id.clone())
            .collect();

        let missing_user_ids: Vec<UserId> = user_ids
            .difference(&loaded_user_ids)
            .cloned()
            .collect();

        if missing_user_ids.len() > 0 {
            return Err(
                ApiError::bad_json(format!(
                    "Unknown users in invite list: {}",
                    &missing_user_ids
                        .iter()
                        .map(|user_id| user_id.to_string())
                        .collect::<Vec<String>>()
                        .join(", ")
                ))
            )
        }

        for user in users {
            let options = RoomMembershipOptions {
                room_id: self.id.clone(),
                user_id: user.id.clone(),
                sender: self.user_id.clone(),
                membership: "invite".to_string(),
            };

            RoomMembership::create(connection, &homeserver_domain, options)?;
        }

        Ok(())
    }
}
<commit_msg>Move m.room.aliases event after m.room.create<commit_after>//! Matrix rooms.

use std::collections::{HashMap, HashSet};
use std::convert::{TryFrom, TryInto};

use diesel::{Connection, ExecuteDsl, ExpressionMethods, FilterDsl, FindDsl, LoadDsl, OrderDsl, insert};
use diesel::pg::PgConnection;
use diesel::pg::data_types::PgTimestamp;
use diesel::pg::expression::dsl::any;
use diesel::result::Error as DieselError;
use ruma_events::EventType;
use ruma_events::room::create::{CreateEvent, CreateEventContent};
use ruma_events::room::history_visibility::{
    HistoryVisibility,
    HistoryVisibilityEvent,
    HistoryVisibilityEventContent,
};
use ruma_events::room::join_rules::{
    JoinRule,
    JoinRulesEvent,
    JoinRulesEventContent,
};
use ruma_events::room::name::{NameEvent, NameEventContent};
use ruma_events::room::power_levels::{PowerLevelsEvent, PowerLevelsEventContent};
use ruma_events::room::topic::{TopicEvent, TopicEventContent};
use ruma_identifiers::{EventId, RoomAliasId, RoomId, UserId};

use error::ApiError;
use models::event::{Event, NewEvent};
use models::room_alias::{NewRoomAlias, RoomAlias};
use models::room_membership::{RoomMembership, RoomMembershipOptions};
use models::user::User;
use schema::{events, rooms, users};

/// Options provided by the user to customize the room upon creation.
pub struct CreationOptions {
    /// An initial alias for the room.
    pub alias: Option<String>,
    /// Whether or not the room should be federated.
    pub federate: bool,
    /// A list of users to invite to the room.
    pub invite_list: Option<Vec<String>>,
    /// An initial name for the room.
    pub name: Option<String>,
    /// A convenience parameter for setting a few default state events.
    pub preset: RoomPreset,
    /// An initial topic for the room.
    pub topic: Option<String>,
}

/// A new Matrix room, not yet saved.
#[derive(Debug, Insertable)]
#[table_name = "rooms"]
pub struct NewRoom {
    /// The room's unique ID.
    pub id: RoomId,
    /// The ID of the user creating the room.
    pub user_id: UserId,
    /// Whether or not the room is visible in the directory.
    pub public: bool,
}

/// A Matrix room.
#[derive(Debug, Queryable)]
pub struct Room {
    /// The room's unique ID.
    pub id: RoomId,
    /// The ID of the user who created the room.
    pub user_id: UserId,
    /// Whether or not the room is visible in the directory.
    pub public: bool,
    /// The time the room was created.
    pub created_at: PgTimestamp,
}

/// A convenience parameter for setting a few default state events.
#[derive(Clone, Copy, Debug, Deserialize)]
pub enum RoomPreset {
    /// `join_rules` is set to `invite` and `history_visibility` is set to `shared`.
    PrivateChat,
    /// `join_rules` is set to `public` and `history_visibility` is set to `shared`.
    PublicChat,
    /// Same as `PrivateChat`, but all initial invitees get the same power level as the creator.
    TrustedPrivateChat,
}

impl Room {
    /// Creates a new room in the database.
    pub fn create(
        connection: &PgConnection,
        new_room: &NewRoom,
        homeserver_domain: &str,
        creation_options: &CreationOptions,
    ) -> Result<Room, ApiError> {
        connection.transaction::<Room, ApiError, _>(|| {
            let room: Room = insert(new_room)
                .into(rooms::table)
                .get_result(connection)
                .map_err(ApiError::from)?;

            let mut new_events = Vec::new();

            let new_create_event: NewEvent = CreateEvent {
                content: CreateEventContent {
                    creator: new_room.user_id.clone(),
                    federate: creation_options.federate,
                },
                event_id: EventId::new(homeserver_domain)?,
                event_type: EventType::RoomCreate,
                prev_content: None,
                room_id: room.id.clone(),
                state_key: "".to_string(),
                unsigned: None,
                user_id: new_room.user_id.clone(),
            }.try_into()?;

            new_events.push(new_create_event);

            if let Some(ref name) = creation_options.name {
                let new_name_event: NewEvent = NameEvent {
                    content: NameEventContent {
                        name: name.to_string(),
                    },
                    event_id: EventId::new(homeserver_domain)?,
                    event_type: EventType::RoomName,
                    prev_content: None,
                    room_id: room.id.clone(),
                    state_key: "".to_string(),
                    unsigned: None,
                    user_id: new_room.user_id.clone(),
                }.try_into()?;

                new_events.push(new_name_event);
            }

            if let Some(ref topic) = creation_options.topic {
                let new_topic_event: NewEvent = TopicEvent {
                    content: TopicEventContent {
                        topic: topic.to_string(),
                    },
                    event_id: EventId::new(homeserver_domain)?,
                    event_type: EventType::RoomTopic,
                    prev_content: None,
                    room_id: room.id.clone(),
                    state_key: "".to_string(),
                    unsigned: None,
                    user_id: new_room.user_id.clone(),
                }.try_into()?;

                new_events.push(new_topic_event);
            }

            let new_history_visibility_event: NewEvent = HistoryVisibilityEvent {
                content: HistoryVisibilityEventContent {
                    history_visibility: HistoryVisibility::Shared,
                },
                event_id: EventId::new(homeserver_domain)?,
                event_type: EventType::RoomHistoryVisibility,
                prev_content: None,
                room_id: room.id.clone(),
                state_key: "".to_string(),
                unsigned: None,
                user_id: new_room.user_id.clone(),
            }.try_into()?;

            new_events.push(new_history_visibility_event);

            match creation_options.preset {
                RoomPreset::PrivateChat => {
                    let new_join_rules_event: NewEvent = JoinRulesEvent {
                        content: JoinRulesEventContent { join_rule: JoinRule::Invite },
                        event_id: EventId::new(homeserver_domain)?,
                        event_type: EventType::RoomJoinRules,
                        prev_content: None,
                        room_id: room.id.clone(),
                        state_key: "".to_string(),
                        unsigned: None,
                        user_id: new_room.user_id.clone(),
                    }.try_into()?;

                    new_events.push(new_join_rules_event);
                }
                RoomPreset::PublicChat => {
                    let new_join_rules_event: NewEvent = JoinRulesEvent {
                        content: JoinRulesEventContent { join_rule: JoinRule::Public },
                        event_id: EventId::new(homeserver_domain)?,
                        event_type: EventType::RoomJoinRules,
                        prev_content: None,
                        room_id: room.id.clone(),
                        state_key: "".to_string(),
                        unsigned: None,
                        user_id: new_room.user_id.clone(),
                    }.try_into()?;

                    new_events.push(new_join_rules_event);
                }
                RoomPreset::TrustedPrivateChat => {
                    let new_join_rules_event: NewEvent = JoinRulesEvent {
                        content: JoinRulesEventContent { join_rule: JoinRule::Invite },
                        event_id: EventId::new(homeserver_domain)?,
                        event_type: EventType::RoomJoinRules,
                        prev_content: None,
                        room_id: room.id.clone(),
                        state_key: "".to_string(),
                        unsigned: None,
                        user_id: new_room.user_id.clone(),
                    }.try_into()?;

                    new_events.push(new_join_rules_event);
                }
            }

            insert(&new_events)
                .into(events::table)
                .execute(connection)
                .map_err(ApiError::from)?;

            if let Some(ref alias) = creation_options.alias {
                let new_room_alias = NewRoomAlias {
                    alias: RoomAliasId::try_from(&format!("#{}:{}", alias, homeserver_domain))?,
                    room_id: room.id.clone(),
                    user_id: new_room.user_id.clone(),
                    servers: vec![homeserver_domain.to_string()],
                };

                RoomAlias::create(connection, homeserver_domain, &new_room_alias)?;
            }

            if let Some(ref invite_list) = creation_options.invite_list {
                room.create_memberships(connection, &invite_list, homeserver_domain)?;
            }

            Ok(room)
        }).map_err(ApiError::from)
    }

    /// Looks up the most recent power levels event for the room.
    ///
    /// If the room does not have a power levels event, a default one is created according to the
    /// specification.
    pub fn current_power_levels(&self, connection: &PgConnection)
    -> Result<PowerLevelsEventContent, ApiError> {
        match events::table
            .filter(events::room_id.eq(self.id.clone()))
            .filter(events::event_type.eq(EventType::RoomPowerLevels.to_string()))
            .order(events::ordering.desc())
            .first::<Event>(connection)
        {
            Ok(event) => {
                let power_levels_event: PowerLevelsEvent = event.try_into()?;

                Ok(power_levels_event.content)
            }
            Err(error) => match error {
                DieselError::NotFound => Ok(PowerLevelsEventContent {
                    ban: 50,
                    events: HashMap::new(),
                    events_default: 0,
                    invite: 50,
                    kick: 50,
                    redact: 50,
                    state_default: 0,
                    users: HashMap::new(),
                    users_default: 0,
                }),
                _ => Err(error.into()),
            },
        }
    }

    /// Look up a `Room` given the `RoomId`.
    pub fn find(connection: &PgConnection, room_id: &RoomId)
    -> Result<Room, ApiError> {
        rooms::table
            .find(room_id)
            .get_result(connection)
            .map(Room::from)
            .map_err(|err| {
                match err {
                    DieselError::NotFound => ApiError::not_found(
                        "The room was not found on this server".to_string()
                    ),
                    _ => ApiError::from(err)
                }
            })
    }

    /// Given a list of invited users create the appropriate `m.room.member` events.
    fn create_memberships(&self, connection: &PgConnection, invite_list: &Vec<String>, homeserver_domain: &str)
    -> Result<(), ApiError> {
        let mut user_ids = HashSet::with_capacity(invite_list.len());

        for invitee in invite_list {
            let user_id = UserId::try_from(invitee)?;

            if user_id.hostname().to_string() != homeserver_domain {
                return Err(
                    ApiError::unimplemented("Federation is not yet supported.".to_string())
                );
            }

            user_ids.insert(user_id);
        }

        let users: Vec<User> = users::table
            .filter(users::id.eq(any(
                user_ids.iter().cloned().collect::<Vec<UserId>>()))
            )
            .get_results(connection)
            .map_err(ApiError::from)?;

        let loaded_user_ids: HashSet<UserId> = users
            .iter()
            .map(|user| user.id.clone())
            .collect();

        let missing_user_ids: Vec<UserId> = user_ids
            .difference(&loaded_user_ids)
            .cloned()
            .collect();

        if missing_user_ids.len() > 0 {
            return Err(
                ApiError::bad_json(format!(
                    "Unknown users in invite list: {}",
                    &missing_user_ids
                        .iter()
                        .map(|user_id| user_id.to_string())
                        .collect::<Vec<String>>()
                        .join(", ")
                ))
            )
        }

        for user in users {
            let options = RoomMembershipOptions {
                room_id: self.id.clone(),
                user_id: user.id.clone(),
                sender: self.user_id.clone(),
                membership: "invite".to_string(),
            };

            RoomMembership::create(connection, &homeserver_domain, options)?;
        }

        Ok(())
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::cmp;
use std::str;
use std::slice;
use std::io::IoResult;
use std::io::MemReader;

use colortype;
use hash::Crc32;
use zlib::ZlibDecoder;

use image;
use image::ImageResult;
use image::ImageDecoder;

use super::filter::unfilter;
use super::PNGSIGNATURE;

macro_rules! io_try(
    ($e:expr) => (
    	match $e {
    		Ok(e) => e,
    		Err(_) => return Err(image::IoError)
    	}
    )
)

#[deriving(PartialEq)]
enum PNGState {
	Start,
	HaveSignature,
	HaveIHDR,
	HavePLTE,
	HaveFirstIDat,
	HaveLastIDat,
	HaveIEND
}

/// The representation of a PNG decoder
///
/// Currently does not support decoding of interlaced images
pub struct PNGDecoder<R> {
	z: ZlibDecoder<IDATReader<R>>,
	crc: Crc32,
	previous: Vec<u8>,
	state: PNGState,

	width: u32,
	height: u32,

	bit_depth: u8,
	colour_type: u8,
	pixel_type: colortype::ColorType,

	palette: Option<Vec<(u8, u8, u8)>>,

	interlace_method: u8,

	chunk_length: u32,
	chunk_type: Vec<u8>,

	bpp: uint,
	rlength: uint,
	decoded_rows: u32,
}

impl<R: Reader> PNGDecoder<R> {
	/// Create a new decoder that decodes from the stream ```r```
	pub fn new(r: R) -> PNGDecoder<R> {
		let idat_reader = IDATReader::new(r);
		PNGDecoder {
			pixel_type: colortype::Grey(1),
			palette: None,

			previous: Vec::new(),
			state: Start,
			z: ZlibDecoder::new(idat_reader),
			crc: Crc32::new(),

			width: 0,
			height: 0,
			bit_depth: 0,
			colour_type: 0,
			interlace_method: 0,

			chunk_length: 0,
			chunk_type: Vec::new(),
			bpp: 0,
			rlength: 0,
			decoded_rows: 0,
		}
	}

	///Returns a reference to the color palette used for indexed
	///color images.
	///Each array element is a tuple of RGB values.
	pub fn palette<'a>(&'a self) -> &'a [(u8, u8, u8)] {
		match self.palette {
			Some(ref p) => p.as_slice(),
			None        => &[]
		}
	}

	fn read_signature(&mut self) -> ImageResult<bool> {
		let png = io_try!(self.z.inner().r.read_exact(8));

		Ok(png.as_slice() == PNGSIGNATURE)
	}

	fn parse_ihdr(&mut self, buf: Vec<u8>) -> ImageResult<()> {
		self.crc.update(buf.as_slice());
		let mut m = MemReader::new(buf);

		self.width = m.read_be_u32().unwrap();
		self.height = m.read_be_u32().unwrap();

		self.bit_depth = m.read_byte().unwrap();
		self.colour_type = m.read_byte().unwrap();

		self.pixel_type = match (self.colour_type, self.bit_depth) {
			(0, 1)  => colortype::Grey(1),
			(0, 2)  => colortype::Grey(2),
			(0, 4)  => colortype::Grey(4),
			(0, 8)  => colortype::Grey(8),
			(0, 16) => colortype::Grey(16),
			(2, 8)  => colortype::RGB(8),
			(2, 16) => colortype::RGB(16),
			(3, 1)  => colortype::RGB(8),
			(3, 2)  => colortype::RGB(8),
			(3, 4)  => colortype::RGB(8),
			(3, 8)  => colortype::RGB(8),
			(4, 8)  => colortype::GreyA(8),
			(4, 16) => colortype::GreyA(16),
			(6, 8)  => colortype::RGBA(8),
			(6, 16) => colortype::RGBA(16),
			(_, _)  => return Err(image::FormatError)
		};

		let compression_method = m.read_byte().unwrap();
		if compression_method != 0 {
			return Err(image::UnsupportedError)
		}

		let filter_method = m.read_byte().unwrap();
		if filter_method != 0 {
			return Err(image::UnsupportedError)
		}

		self.interlace_method = m.read_byte().unwrap();
		if self.interlace_method != 0 {
			return Err(image::UnsupportedError)
		}

		let channels = match self.colour_type {
			0 => 1,
			2 => 3,
			3 => 1,
			4 => 2,
			6 => 4,
			_ => return Err(image::FormatError)
		};

		let bits_per_pixel = channels * self.bit_depth as uint;

		self.rlength = (bits_per_pixel * self.width as uint + 7) / 8;
		self.bpp = (bits_per_pixel + 7) / 8;
		self.previous = Vec::from_elem(self.rlength as uint, 0u8);

		Ok(())
	}

	fn parse_plte(&mut self, buf: Vec<u8>) -> ImageResult<()> {
		self.crc.update(buf.as_slice());

		let len = buf.len() / 3;

		if len > 256 || len > (1 << self.bit_depth) || buf.len() % 3 != 0{
			return Err(image::FormatError)
		}

		let p = Vec::from_fn(256, |i| {
			if i < len {
				let r = buf.as_slice()[3 * i];
				let g = buf.as_slice()[3 * i + 1];
				let b = buf.as_slice()[3 * i + 2];

				(r, g, b)
			}
			else {
				(0, 0, 0)
			}
		});

		self.palette = Some(p);

		Ok(())
	}

	fn read_metadata(&mut self) -> ImageResult<()> {
		if !try!(self.read_signature()) {
			return Err(image::FormatError)
		}

		self.state = HaveSignature;

		loop {
			let length = io_try!(self.z.inner().r.read_be_u32());
			let chunk  = io_try!(self.z.inner().r.read_exact(4));

			self.chunk_length = length;
			self.chunk_type   = chunk.clone();

			self.crc.update(chunk);

			let s = {
				let a = str::from_utf8_owned(self.chunk_type.clone());
				a.unwrap()
			};

			match (s.as_slice(), self.state) {
				("IHDR", HaveSignature) => {
					if length != 13 {
						return Err(image::FormatError)
					}

					let d = io_try!(self.z.inner().r.read_exact(length as uint));
					let _ = try!(self.parse_ihdr(d));

					self.state = HaveIHDR;
				}

				("PLTE", HaveIHDR) => {
					let d = io_try!(self.z.inner().r.read_exact(length as uint));
					let _ = try!(self.parse_plte(d));
					self.state = HavePLTE;
				}

				("tRNS", HavePLTE) => {
					return Err(image::UnsupportedError)
				}

				("IDAT", HaveIHDR) if self.colour_type != 3 => {
					self.state = HaveFirstIDat;
					self.z.inner().set_inital_length(self.chunk_length);
					self.z.inner().crc.update(self.chunk_type.as_slice());

					break;
				}

				("IDAT", HavePLTE) if self.colour_type == 3 => {
					self.state = HaveFirstIDat;
					self.z.inner().set_inital_length(self.chunk_length);
					self.z.inner().crc.update(self.chunk_type.as_slice());

					break;
				}

				_ => {
					let b = io_try!(self.z.inner().r.read_exact(length as uint));
					self.crc.update(b);
				}
			}

			let chunk_crc = io_try!(self.z.inner().r.read_be_u32());
			let crc = self.crc.checksum();

			if crc != chunk_crc {
				return Err(image::FormatError)
			}

			self.crc.reset();
		}

		Ok(())
	}
}

impl<R: Reader> ImageDecoder for PNGDecoder<R> {
	fn dimensions(&mut self) -> ImageResult<(u32, u32)> {
		if self.state == Start {
			let _ = try!(self.read_metadata());
		}

		Ok((self.width, self.height))
	}

	fn colortype(&mut self) -> ImageResult<colortype::ColorType> {
		if self.state == Start {
			let _ = try!(self.read_metadata());
		}

		Ok(self.pixel_type)
	}

	fn row_len(&mut self) -> ImageResult<uint> {
		if self.state == Start {
			let _ = try!(self.read_metadata());
		}

		let bits = colortype::bits_per_pixel(self.pixel_type);

		Ok((bits * self.width as uint + 7) / 8)
	}

	fn read_scanline(&mut self, buf: &mut [u8]) -> ImageResult<u32> {
		if self.state == Start {
			let _ = try!(self.read_metadata());
		}

        let filter_type = match FromPrimitive::from_u8(io_try!(self.z.read_byte())) {
            Some(v) => v,
			_ => return Err(image::FormatError)
		};
		let mut read = 0;
		while read < self.rlength {
			let r = io_try!(self.z.read(buf.mut_slice_from(read)));
			read += r;
		}

		unfilter(filter_type, self.bpp, self.previous.as_slice(), buf.mut_slice_to(self.rlength));
		slice::bytes::copy_memory(self.previous.as_mut_slice(), buf.slice_to(self.rlength));

		if self.palette.is_some() {
			let s = (*self.palette.get_ref()).as_slice();
			expand_palette(buf, s, self.rlength);
		}

		self.decoded_rows += 1;

		Ok(self.decoded_rows)
	}

	fn read_image(&mut self) -> ImageResult<Vec<u8>> {
		if self.state == Start {
			let _ = try!(self.read_metadata());
		}

		let rowlen  = try!(self.row_len());
		let mut buf = Vec::from_elem(rowlen * self.height as uint, 0u8);

		for chunk in buf.as_mut_slice().mut_chunks(rowlen) {
			let _ = try!(self.read_scanline(chunk));
		}

		Ok(buf)
	}
}

fn expand_palette(buf: &mut[u8], palette: &[(u8, u8, u8)], entries: uint) {
	assert!(buf.len() == entries * 3);
	let tmp = Vec::from_fn(entries, |i| buf[i]);

	for (chunk, &i) in buf.mut_chunks(3).zip(tmp.iter()) {
		let (r, g, b) = palette[i as uint];
		chunk[0] = r;
		chunk[1] = g;
		chunk[2] = b;
	}
}

pub struct IDATReader<R> {
	pub r: R,
	pub crc: Crc32,

	eof: bool,
	chunk_length: u32,
}

impl<R:Reader> IDATReader<R> {
	pub fn new(r: R) -> IDATReader<R> {
		IDATReader {
			r: r,
			crc: Crc32::new(),
			eof: false,
			chunk_length: 0,
		}
	}

	pub fn set_inital_length(&mut self, len: u32) {
		self.chunk_length = len;
	}
}

impl<R: Reader> Reader for IDATReader<R> {
	fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
		if self.eof {
			return Err(io::standard_error(io::EndOfFile))
		}

		let len = buf.len();
		let mut start = 0;

		while start < len {
			while self.chunk_length == 0 {
				let chunk_crc = try!(self.r.read_be_u32());
				let crc = self.crc.checksum();

				if crc != chunk_crc {
					return Err(io::standard_error(io::InvalidInput))
				}

				self.crc.reset();

				self.chunk_length = try!(self.r.read_be_u32());

				let v = try!(self.r.read_exact(4));
				self.crc.update(v.as_slice());

				match str::from_utf8(v.as_slice()) {
					Some("IDAT") => (),
					_ 	     => {
						self.eof = true;
						break
					}
				}
			}

			let m = cmp::min(len - start, self.chunk_length as uint);

			let slice = buf.mut_slice(start, start + m);
			let r = try!(self.r.read(slice));

			start += r;

			self.chunk_length -= r as u32;
			self.crc.update(slice.as_slice());
		}

		Ok(start)
	}
}
<commit_msg>formatting: spaces to tabs<commit_after>use std::io;
use std::cmp;
use std::str;
use std::slice;
use std::io::IoResult;
use std::io::MemReader;

use colortype;
use hash::Crc32;
use zlib::ZlibDecoder;

use image;
use image::ImageResult;
use image::ImageDecoder;

use super::filter::unfilter;
use super::PNGSIGNATURE;

macro_rules! io_try(
    ($e:expr) => (
    	match $e {
    		Ok(e) => e,
    		Err(_) => return Err(image::IoError)
    	}
    )
)

#[deriving(PartialEq)]
enum PNGState {
	Start,
	HaveSignature,
	HaveIHDR,
	HavePLTE,
	HaveFirstIDat,
	HaveLastIDat,
	HaveIEND
}

/// The representation of a PNG decoder
///
/// Currently does not support decoding of interlaced images
pub struct PNGDecoder<R> {
	z: ZlibDecoder<IDATReader<R>>,
	crc: Crc32,
	previous: Vec<u8>,
	state: PNGState,

	width: u32,
	height: u32,

	bit_depth: u8,
	colour_type: u8,
	pixel_type: colortype::ColorType,

	palette: Option<Vec<(u8, u8, u8)>>,

	interlace_method: u8,

	chunk_length: u32,
	chunk_type: Vec<u8>,

	bpp: uint,
	rlength: uint,
	decoded_rows: u32,
}

impl<R: Reader> PNGDecoder<R> {
	/// Create a new decoder that decodes from the stream ```r```
	pub fn new(r: R) -> PNGDecoder<R> {
		let idat_reader = IDATReader::new(r);
		PNGDecoder {
			pixel_type: colortype::Grey(1),
			palette: None,

			previous: Vec::new(),
			state: Start,
			z: ZlibDecoder::new(idat_reader),
			crc: Crc32::new(),

			width: 0,
			height: 0,
			bit_depth: 0,
			colour_type: 0,
			interlace_method: 0,

			chunk_length: 0,
			chunk_type: Vec::new(),
			bpp: 0,
			rlength: 0,
			decoded_rows: 0,
		}
	}

	///Returns a reference to the color palette used for indexed
	///color images.
	///Each array element is a tuple of RGB values.
	pub fn palette<'a>(&'a self) -> &'a [(u8, u8, u8)] {
		match self.palette {
			Some(ref p) => p.as_slice(),
			None        => &[]
		}
	}

	fn read_signature(&mut self) -> ImageResult<bool> {
		let png = io_try!(self.z.inner().r.read_exact(8));

		Ok(png.as_slice() == PNGSIGNATURE)
	}

	fn parse_ihdr(&mut self, buf: Vec<u8>) -> ImageResult<()> {
		self.crc.update(buf.as_slice());
		let mut m = MemReader::new(buf);

		self.width = m.read_be_u32().unwrap();
		self.height = m.read_be_u32().unwrap();

		self.bit_depth = m.read_byte().unwrap();
		self.colour_type = m.read_byte().unwrap();

		self.pixel_type = match (self.colour_type, self.bit_depth) {
			(0, 1)  => colortype::Grey(1),
			(0, 2)  => colortype::Grey(2),
			(0, 4)  => colortype::Grey(4),
			(0, 8)  => colortype::Grey(8),
			(0, 16) => colortype::Grey(16),
			(2, 8)  => colortype::RGB(8),
			(2, 16) => colortype::RGB(16),
			(3, 1)  => colortype::RGB(8),
			(3, 2)  => colortype::RGB(8),
			(3, 4)  => colortype::RGB(8),
			(3, 8)  => colortype::RGB(8),
			(4, 8)  => colortype::GreyA(8),
			(4, 16) => colortype::GreyA(16),
			(6, 8)  => colortype::RGBA(8),
			(6, 16) => colortype::RGBA(16),
			(_, _)  => return Err(image::FormatError)
		};

		let compression_method = m.read_byte().unwrap();
		if compression_method != 0 {
			return Err(image::UnsupportedError)
		}

		let filter_method = m.read_byte().unwrap();
		if filter_method != 0 {
			return Err(image::UnsupportedError)
		}

		self.interlace_method = m.read_byte().unwrap();
		if self.interlace_method != 0 {
			return Err(image::UnsupportedError)
		}

		let channels = match self.colour_type {
			0 => 1,
			2 => 3,
			3 => 1,
			4 => 2,
			6 => 4,
			_ => return Err(image::FormatError)
		};

		let bits_per_pixel = channels * self.bit_depth as uint;

		self.rlength = (bits_per_pixel * self.width as uint + 7) / 8;
		self.bpp = (bits_per_pixel + 7) / 8;
		self.previous = Vec::from_elem(self.rlength as uint, 0u8);

		Ok(())
	}

	fn parse_plte(&mut self, buf: Vec<u8>) -> ImageResult<()> {
		self.crc.update(buf.as_slice());

		let len = buf.len() / 3;

		if len > 256 || len > (1 << self.bit_depth) || buf.len() % 3 != 0{
			return Err(image::FormatError)
		}

		let p = Vec::from_fn(256, |i| {
			if i < len {
				let r = buf.as_slice()[3 * i];
				let g = buf.as_slice()[3 * i + 1];
				let b = buf.as_slice()[3 * i + 2];

				(r, g, b)
			}
			else {
				(0, 0, 0)
			}
		});

		self.palette = Some(p);

		Ok(())
	}

	fn read_metadata(&mut self) -> ImageResult<()> {
		if !try!(self.read_signature()) {
			return Err(image::FormatError)
		}

		self.state = HaveSignature;

		loop {
			let length = io_try!(self.z.inner().r.read_be_u32());
			let chunk  = io_try!(self.z.inner().r.read_exact(4));

			self.chunk_length = length;
			self.chunk_type   = chunk.clone();

			self.crc.update(chunk);

			let s = {
				let a = str::from_utf8_owned(self.chunk_type.clone());
				a.unwrap()
			};

			match (s.as_slice(), self.state) {
				("IHDR", HaveSignature) => {
					if length != 13 {
						return Err(image::FormatError)
					}

					let d = io_try!(self.z.inner().r.read_exact(length as uint));
					try!(self.parse_ihdr(d));

					self.state = HaveIHDR;
				}

				("PLTE", HaveIHDR) => {
					let d = io_try!(self.z.inner().r.read_exact(length as uint));
					try!(self.parse_plte(d));
					self.state = HavePLTE;
				}

				("tRNS", HavePLTE) => {
					return Err(image::UnsupportedError)
				}

				("IDAT", HaveIHDR) if self.colour_type != 3 => {
					self.state = HaveFirstIDat;
					self.z.inner().set_inital_length(self.chunk_length);
					self.z.inner().crc.update(self.chunk_type.as_slice());

					break;
				}

				("IDAT", HavePLTE) if self.colour_type == 3 => {
					self.state = HaveFirstIDat;
					self.z.inner().set_inital_length(self.chunk_length);
					self.z.inner().crc.update(self.chunk_type.as_slice());

					break;
				}

				_ => {
					let b = io_try!(self.z.inner().r.read_exact(length as uint));
					self.crc.update(b);
				}
			}

			let chunk_crc = io_try!(self.z.inner().r.read_be_u32());
			let crc = self.crc.checksum();

			if crc != chunk_crc {
				return Err(image::FormatError)
			}

			self.crc.reset();
		}

		Ok(())
	}
}

impl<R: Reader> ImageDecoder for PNGDecoder<R> {
	fn dimensions(&mut self) -> ImageResult<(u32, u32)> {
		if self.state == Start {
			let _ = try!(self.read_metadata());
		}

		Ok((self.width, self.height))
	}

	fn colortype(&mut self) -> ImageResult<colortype::ColorType> {
		if self.state == Start {
			let _ = try!(self.read_metadata());
		}

		Ok(self.pixel_type)
	}

	fn row_len(&mut self) -> ImageResult<uint> {
		if self.state == Start {
			let _ = try!(self.read_metadata());
		}

		let bits = colortype::bits_per_pixel(self.pixel_type);

		Ok((bits * self.width as uint + 7) / 8)
	}

	fn read_scanline(&mut self, buf: &mut [u8]) -> ImageResult<u32> {
		if self.state == Start {
			let _ = try!(self.read_metadata());
		}

		let filter_type = match FromPrimitive::from_u8(io_try!(self.z.read_byte())) {
			Some(v) => v,
			_ => return Err(image::FormatError)
		};

		let mut read = 0;
		while read < self.rlength {
			let r = io_try!(self.z.read(buf.mut_slice_from(read)));
			read += r;
		}

		unfilter(filter_type, self.bpp, self.previous.as_slice(), buf.mut_slice_to(self.rlength));
		slice::bytes::copy_memory(self.previous.as_mut_slice(), buf.slice_to(self.rlength));

		if self.palette.is_some() {
			let s = (*self.palette.get_ref()).as_slice();
			expand_palette(buf, s, self.rlength);
		}

		self.decoded_rows += 1;

		Ok(self.decoded_rows)
	}

	fn read_image(&mut self) -> ImageResult<Vec<u8>> {
		if self.state == Start {
			let _ = try!(self.read_metadata());
		}

		let rowlen  = try!(self.row_len());
		let mut buf = Vec::from_elem(rowlen * self.height as uint, 0u8);

		for chunk in buf.as_mut_slice().mut_chunks(rowlen) {
			let _ = try!(self.read_scanline(chunk));
		}

		Ok(buf)
	}
}

fn expand_palette(buf: &mut[u8], palette: &[(u8, u8, u8)], entries: uint) {
	assert!(buf.len() == entries * 3);
	let tmp = Vec::from_fn(entries, |i| buf[i]);

	for (chunk, &i) in buf.mut_chunks(3).zip(tmp.iter()) {
		let (r, g, b) = palette[i as uint];
		chunk[0] = r;
		chunk[1] = g;
		chunk[2] = b;
	}
}

pub struct IDATReader<R> {
	pub r: R,
	pub crc: Crc32,

	eof: bool,
	chunk_length: u32,
}

impl<R:Reader> IDATReader<R> {
	pub fn new(r: R) -> IDATReader<R> {
		IDATReader {
			r: r,
			crc: Crc32::new(),
			eof: false,
			chunk_length: 0,
		}
	}

	pub fn set_inital_length(&mut self, len: u32) {
		self.chunk_length = len;
	}
}

impl<R: Reader> Reader for IDATReader<R> {
	fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
		if self.eof {
			return Err(io::standard_error(io::EndOfFile))
		}

		let len = buf.len();
		let mut start = 0;

		while start < len {
			while self.chunk_length == 0 {
				let chunk_crc = try!(self.r.read_be_u32());
				let crc = self.crc.checksum();

				if crc != chunk_crc {
					return Err(io::standard_error(io::InvalidInput))
				}

				self.crc.reset();

				self.chunk_length = try!(self.r.read_be_u32());

				let v = try!(self.r.read_exact(4));
				self.crc.update(v.as_slice());

				match str::from_utf8(v.as_slice()) {
					Some("IDAT") => (),
					_ 	     => {
						self.eof = true;
						break
					}
				}
			}

			let m = cmp::min(len - start, self.chunk_length as uint);

			let slice = buf.mut_slice(start, start + m);
			let r = try!(self.r.read(slice));

			start += r;

			self.chunk_length -= r as u32;
			self.crc.update(slice.as_slice());
		}

		Ok(start)
	}
}
<|endoftext|>


<commit_before>use clap::{App, AppSettings, Arg, SubCommand};
use error::Error;
use glob::glob;
use std::path::Path;
use std::process::exit;
use std::{env, fs, u64};
use tree_sitter::Language;
use tree_sitter_cli::{
    config, error, generate, highlight, loader, logger, parse, query, test, test_highlight, wasm,
    web_ui,
};

const BUILD_VERSION: &'static str = env!("CARGO_PKG_VERSION");
const BUILD_SHA: Option<&'static str> = option_env!("BUILD_SHA");

fn main() {
    if let Err(e) = run() {
        if !e.message().is_empty() {
            println!("");
            eprintln!("{}", e.message());
        }
        exit(1);
    }
}

fn run() -> error::Result<()> {
    let version = if let Some(build_sha) = BUILD_SHA {
        format!("{} ({})", BUILD_VERSION, build_sha)
    } else {
        BUILD_VERSION.to_string()
    };

    let matches = App::new("tree-sitter")
        .version(version.as_str())
        .setting(AppSettings::SubcommandRequiredElseHelp)
        .author("Max Brunsfeld <maxbrunsfeld@gmail.com>")
        .about("Generates and tests parsers")
        .subcommand(SubCommand::with_name("init-config").about("Generate a default config file"))
        .subcommand(
            SubCommand::with_name("generate")
                .about("Generate a parser")
                .arg(Arg::with_name("grammar-path").index(1))
                .arg(Arg::with_name("log").long("log"))
                .arg(Arg::with_name("next-abi").long("next-abi"))
                .arg(
                    Arg::with_name("report-states-for-rule")
                        .long("report-states-for-rule")
                        .value_name("rule-name")
                        .takes_value(true),
                )
                .arg(Arg::with_name("no-minimize").long("no-minimize")),
        )
        .subcommand(
            SubCommand::with_name("parse")
                .about("Parse files")
                .arg(
                    Arg::with_name("path")
                        .index(1)
                        .multiple(true)
                        .required(true),
                )
                .arg(Arg::with_name("scope").long("scope").takes_value(true))
                .arg(Arg::with_name("debug").long("debug").short("d"))
                .arg(Arg::with_name("debug-graph").long("debug-graph").short("D"))
                .arg(Arg::with_name("quiet").long("quiet").short("q"))
                .arg(Arg::with_name("time").long("time").short("t"))
                .arg(Arg::with_name("allow-cancellation").long("cancel"))
                .arg(Arg::with_name("files-").long("cancel"))
                .arg(Arg::with_name("timeout").long("timeout").takes_value(true))
                .arg(
                    Arg::with_name("edits")
                        .long("edit")
                        .short("edit")
                        .takes_value(true)
                        .multiple(true)
                        .number_of_values(1),
                ),
        )
        .subcommand(
            SubCommand::with_name("query")
                .about("Search files using a syntax tree query")
                .arg(Arg::with_name("query-path").index(1).required(true))
                .arg(
                    Arg::with_name("path")
                        .index(2)
                        .multiple(true)
                        .required(true),
                )
                .arg(Arg::with_name("scope").long("scope").takes_value(true))
                .arg(Arg::with_name("captures").long("captures").short("c")),
        )
        .subcommand(
            SubCommand::with_name("test")
                .about("Run a parser's tests")
                .arg(
                    Arg::with_name("filter")
                        .long("filter")
                        .short("f")
                        .takes_value(true),
                )
                .arg(Arg::with_name("debug").long("debug").short("d"))
                .arg(Arg::with_name("debug-graph").long("debug-graph").short("D")),
        )
        .subcommand(
            SubCommand::with_name("highlight")
                .about("Highlight a file")
                .arg(
                    Arg::with_name("path")
                        .index(1)
                        .multiple(true)
                        .required(true),
                )
                .arg(Arg::with_name("scope").long("scope").takes_value(true))
                .arg(Arg::with_name("html").long("html").short("h"))
                .arg(Arg::with_name("time").long("time").short("t"))
                .arg(Arg::with_name("q").short("q")),
        )
        .subcommand(
            SubCommand::with_name("build-wasm")
                .about("Compile a parser to WASM")
                .arg(
                    Arg::with_name("docker")
                        .long("docker")
                        .help("Run emscripten via docker even if it is installed locally"),
                )
                .arg(Arg::with_name("path").index(1).multiple(true)),
        )
        .subcommand(
            SubCommand::with_name("web-ui").about("Test a parser interactively in the browser"),
        )
        .subcommand(
            SubCommand::with_name("dump-languages")
                .about("Print info about all known language parsers"),
        )
        .get_matches();

    let home_dir = dirs::home_dir().expect("Failed to read home directory");
    let current_dir = env::current_dir().unwrap();
    let config = config::Config::load(&home_dir);
    let mut loader = loader::Loader::new(config.binary_directory.clone());

    if matches.subcommand_matches("init-config").is_some() {
        let config = config::Config::new(&home_dir);
        config.save(&home_dir)?;
    } else if let Some(matches) = matches.subcommand_matches("generate") {
        let grammar_path = matches.value_of("grammar-path");
        let report_symbol_name = matches.value_of("report-states-for-rule").or_else(|| {
            if matches.is_present("report-states") {
                Some("")
            } else {
                None
            }
        });
        if matches.is_present("log") {
            logger::init();
        }
        let next_abi = matches.is_present("next-abi");
        generate::generate_parser_in_directory(
            &current_dir,
            grammar_path,
            next_abi,
            report_symbol_name,
        )?;
    } else if let Some(matches) = matches.subcommand_matches("test") {
        let debug = matches.is_present("debug");
        let debug_graph = matches.is_present("debug-graph");
        let filter = matches.value_of("filter");
        let languages = loader.languages_at_path(&current_dir)?;
        let language = languages
            .first()
            .ok_or_else(|| "No language found".to_string())?;
        let test_dir = current_dir.join("test");

        // Run the corpus tests. Look for them at two paths: `test/corpus` and `corpus`.
        let mut test_corpus_dir = test_dir.join("corpus");
        if !test_corpus_dir.is_dir() {
            test_corpus_dir = current_dir.join("corpus");
        }
        if test_corpus_dir.is_dir() {
            test::run_tests_at_path(*language, &test_corpus_dir, debug, debug_graph, filter)?;
        }

        // Check that all of the queries are valid.
        test::check_queries_at_path(*language, &current_dir.join("queries"))?;

        // Run the syntax highlighting tests.
        let test_highlight_dir = test_dir.join("highlight");
        if test_highlight_dir.is_dir() {
            test_highlight::test_highlights(&loader, &test_highlight_dir)?;
        }
    } else if let Some(matches) = matches.subcommand_matches("parse") {
        let debug = matches.is_present("debug");
        let debug_graph = matches.is_present("debug-graph");
        let quiet = matches.is_present("quiet");
        let time = matches.is_present("time");
        let edits = matches
            .values_of("edits")
            .map_or(Vec::new(), |e| e.collect());
        let allow_cancellation = matches.is_present("allow-cancellation");
        let timeout = matches
            .value_of("timeout")
            .map_or(0, |t| u64::from_str_radix(t, 10).unwrap());
        let paths = collect_paths(matches.values_of("path").unwrap())?;
        let max_path_length = paths.iter().map(|p| p.chars().count()).max().unwrap();
        let mut has_error = false;
        loader.find_all_languages(&config.parser_directories)?;
        for path in paths {
            let path = Path::new(&path);
            let language =
                select_language(&mut loader, path, &current_dir, matches.value_of("scope"))?;
            has_error |= parse::parse_file_at_path(
                language,
                path,
                &edits,
                max_path_length,
                quiet,
                time,
                timeout,
                debug,
                debug_graph,
                allow_cancellation,
            )?;
        }
        if has_error {
            return Error::err(String::new());
        }
    } else if let Some(matches) = matches.subcommand_matches("query") {
        let ordered_captures = matches.values_of("captures").is_some();
        let paths = matches
            .values_of("path")
            .unwrap()
            .into_iter()
            .map(Path::new)
            .collect::<Vec<&Path>>();
        loader.find_all_languages(&config.parser_directories)?;
        let language = select_language(
            &mut loader,
            paths[0],
            &current_dir,
            matches.value_of("scope"),
        )?;
        let query_path = Path::new(matches.value_of("query-path").unwrap());
        query::query_files_at_paths(language, paths, query_path, ordered_captures)?;
    } else if let Some(matches) = matches.subcommand_matches("highlight") {
        loader.configure_highlights(&config.theme.highlight_names);
        loader.find_all_languages(&config.parser_directories)?;

        let time = matches.is_present("time");
        let paths = matches.values_of("path").unwrap().into_iter();
        let html_mode = matches.is_present("html");
        if html_mode {
            println!("{}", highlight::HTML_HEADER);
        }

        let language_config;
        if let Some(scope) = matches.value_of("scope") {
            language_config = loader.language_configuration_for_scope(scope)?;
            if language_config.is_none() {
                return Error::err(format!("Unknown scope '{}'", scope));
            }
        } else {
            language_config = None;
        }

        for path in paths {
            let path = Path::new(path);
            let (language, language_config) = match language_config {
                Some(v) => v,
                None => match loader.language_configuration_for_file_name(path)? {
                    Some(v) => v,
                    None => {
                        eprintln!("No language found for path {:?}", path);
                        continue;
                    }
                },
            };

            let source = fs::read(path)?;

            if let Some(highlight_config) = language_config.highlight_config(language)? {
                if html_mode {
                    highlight::html(&loader, &config.theme, &source, highlight_config, time)?;
                } else {
                    highlight::ansi(&loader, &config.theme, &source, highlight_config, time)?;
                }
            } else {
                return Error::err(format!("No syntax highlighting query found"));
            }
        }
    } else if let Some(matches) = matches.subcommand_matches("build-wasm") {
        let grammar_path = current_dir.join(matches.value_of("path").unwrap_or(""));
        wasm::compile_language_to_wasm(&grammar_path, matches.is_present("docker"))?;
    } else if matches.subcommand_matches("web-ui").is_some() {
        web_ui::serve(&current_dir);
    } else if matches.subcommand_matches("dump-languages").is_some() {
        loader.find_all_languages(&config.parser_directories)?;
        for (configuration, language_path) in loader.get_all_language_configurations() {
            println!(
                concat!(
                    "scope: {}\n",
                    "parser: {:?}\n",
                    "highlights: {:?}\n",
                    "file_types: {:?}\n",
                    "content_regex: {:?}\n",
                    "injection_regex: {:?}\n",
                ),
                configuration.scope.as_ref().unwrap_or(&String::new()),
                language_path,
                configuration.highlights_filenames,
                configuration.file_types,
                configuration.content_regex,
                configuration.injection_regex,
            );
        }
    }

    Ok(())
}

fn collect_paths<'a>(paths: impl Iterator<Item = &'a str>) -> error::Result<Vec<String>> {
    let mut result = Vec::new();

    let mut incorporate_path = |path: &str, positive| {
        if positive {
            result.push(path.to_string());
        } else {
            if let Some(index) = result.iter().position(|p| p == path) {
                result.remove(index);
            }
        }
    };

    for mut path in paths {
        let mut positive = true;
        if path.starts_with("!") {
            positive = false;
            path = path.trim_start_matches("!");
        }

        if Path::new(path).exists() {
            incorporate_path(path, positive);
        } else {
            for path in glob(path)? {
                if let Some(path) = path?.to_str() {
                    incorporate_path(path, positive);
                }
            }
        }
    }
    Ok(result)
}

fn select_language(
    loader: &mut loader::Loader,
    path: &Path,
    current_dir: &Path,
    scope: Option<&str>,
) -> Result<Language, Error> {
    if let Some(scope) = scope {
        if let Some(config) =
            loader
                .language_configuration_for_scope(scope)
                .map_err(Error::wrap(|| {
                    format!("Failed to load language for scope '{}'", scope)
                }))?
        {
            Ok(config.0)
        } else {
            return Error::err(format!("Unknown scope '{}'", scope));
        }
    } else if let Some((lang, _)) =
        loader
            .language_configuration_for_file_name(path)
            .map_err(Error::wrap(|| {
                format!(
                    "Failed to load language for file name {:?}",
                    path.file_name().unwrap()
                )
            }))?
    {
        Ok(lang)
    } else if let Some(lang) = loader
        .languages_at_path(&current_dir)
        .map_err(Error::wrap(|| {
            "Failed to load language in current directory"
        }))?
        .first()
        .cloned()
    {
        Ok(lang)
    } else {
        eprintln!("No language found");
        Error::err("No language found".to_string())
    }
}
<commit_msg>cli: Generate parseres with the new ABI by default<commit_after>use clap::{App, AppSettings, Arg, SubCommand};
use error::Error;
use glob::glob;
use std::path::Path;
use std::process::exit;
use std::{env, fs, u64};
use tree_sitter::Language;
use tree_sitter_cli::{
    config, error, generate, highlight, loader, logger, parse, query, test, test_highlight, wasm,
    web_ui,
};

const BUILD_VERSION: &'static str = env!("CARGO_PKG_VERSION");
const BUILD_SHA: Option<&'static str> = option_env!("BUILD_SHA");

fn main() {
    if let Err(e) = run() {
        if !e.message().is_empty() {
            println!("");
            eprintln!("{}", e.message());
        }
        exit(1);
    }
}

fn run() -> error::Result<()> {
    let version = if let Some(build_sha) = BUILD_SHA {
        format!("{} ({})", BUILD_VERSION, build_sha)
    } else {
        BUILD_VERSION.to_string()
    };

    let matches = App::new("tree-sitter")
        .version(version.as_str())
        .setting(AppSettings::SubcommandRequiredElseHelp)
        .author("Max Brunsfeld <maxbrunsfeld@gmail.com>")
        .about("Generates and tests parsers")
        .subcommand(SubCommand::with_name("init-config").about("Generate a default config file"))
        .subcommand(
            SubCommand::with_name("generate")
                .about("Generate a parser")
                .arg(Arg::with_name("grammar-path").index(1))
                .arg(Arg::with_name("log").long("log"))
                .arg(Arg::with_name("prev-abi").long("prev-abi"))
                .arg(
                    Arg::with_name("report-states-for-rule")
                        .long("report-states-for-rule")
                        .value_name("rule-name")
                        .takes_value(true),
                )
                .arg(Arg::with_name("no-minimize").long("no-minimize")),
        )
        .subcommand(
            SubCommand::with_name("parse")
                .about("Parse files")
                .arg(
                    Arg::with_name("path")
                        .index(1)
                        .multiple(true)
                        .required(true),
                )
                .arg(Arg::with_name("scope").long("scope").takes_value(true))
                .arg(Arg::with_name("debug").long("debug").short("d"))
                .arg(Arg::with_name("debug-graph").long("debug-graph").short("D"))
                .arg(Arg::with_name("quiet").long("quiet").short("q"))
                .arg(Arg::with_name("time").long("time").short("t"))
                .arg(Arg::with_name("allow-cancellation").long("cancel"))
                .arg(Arg::with_name("files-").long("cancel"))
                .arg(Arg::with_name("timeout").long("timeout").takes_value(true))
                .arg(
                    Arg::with_name("edits")
                        .long("edit")
                        .short("edit")
                        .takes_value(true)
                        .multiple(true)
                        .number_of_values(1),
                ),
        )
        .subcommand(
            SubCommand::with_name("query")
                .about("Search files using a syntax tree query")
                .arg(Arg::with_name("query-path").index(1).required(true))
                .arg(
                    Arg::with_name("path")
                        .index(2)
                        .multiple(true)
                        .required(true),
                )
                .arg(Arg::with_name("scope").long("scope").takes_value(true))
                .arg(Arg::with_name("captures").long("captures").short("c")),
        )
        .subcommand(
            SubCommand::with_name("test")
                .about("Run a parser's tests")
                .arg(
                    Arg::with_name("filter")
                        .long("filter")
                        .short("f")
                        .takes_value(true),
                )
                .arg(Arg::with_name("debug").long("debug").short("d"))
                .arg(Arg::with_name("debug-graph").long("debug-graph").short("D")),
        )
        .subcommand(
            SubCommand::with_name("highlight")
                .about("Highlight a file")
                .arg(
                    Arg::with_name("path")
                        .index(1)
                        .multiple(true)
                        .required(true),
                )
                .arg(Arg::with_name("scope").long("scope").takes_value(true))
                .arg(Arg::with_name("html").long("html").short("h"))
                .arg(Arg::with_name("time").long("time").short("t"))
                .arg(Arg::with_name("q").short("q")),
        )
        .subcommand(
            SubCommand::with_name("build-wasm")
                .about("Compile a parser to WASM")
                .arg(
                    Arg::with_name("docker")
                        .long("docker")
                        .help("Run emscripten via docker even if it is installed locally"),
                )
                .arg(Arg::with_name("path").index(1).multiple(true)),
        )
        .subcommand(
            SubCommand::with_name("web-ui").about("Test a parser interactively in the browser"),
        )
        .subcommand(
            SubCommand::with_name("dump-languages")
                .about("Print info about all known language parsers"),
        )
        .get_matches();

    let home_dir = dirs::home_dir().expect("Failed to read home directory");
    let current_dir = env::current_dir().unwrap();
    let config = config::Config::load(&home_dir);
    let mut loader = loader::Loader::new(config.binary_directory.clone());

    if matches.subcommand_matches("init-config").is_some() {
        let config = config::Config::new(&home_dir);
        config.save(&home_dir)?;
    } else if let Some(matches) = matches.subcommand_matches("generate") {
        let grammar_path = matches.value_of("grammar-path");
        let report_symbol_name = matches.value_of("report-states-for-rule").or_else(|| {
            if matches.is_present("report-states") {
                Some("")
            } else {
                None
            }
        });
        if matches.is_present("log") {
            logger::init();
        }
        let prev_abi = matches.is_present("prev-abi");
        generate::generate_parser_in_directory(
            &current_dir,
            grammar_path,
            !prev_abi,
            report_symbol_name,
        )?;
    } else if let Some(matches) = matches.subcommand_matches("test") {
        let debug = matches.is_present("debug");
        let debug_graph = matches.is_present("debug-graph");
        let filter = matches.value_of("filter");
        let languages = loader.languages_at_path(&current_dir)?;
        let language = languages
            .first()
            .ok_or_else(|| "No language found".to_string())?;
        let test_dir = current_dir.join("test");

        // Run the corpus tests. Look for them at two paths: `test/corpus` and `corpus`.
        let mut test_corpus_dir = test_dir.join("corpus");
        if !test_corpus_dir.is_dir() {
            test_corpus_dir = current_dir.join("corpus");
        }
        if test_corpus_dir.is_dir() {
            test::run_tests_at_path(*language, &test_corpus_dir, debug, debug_graph, filter)?;
        }

        // Check that all of the queries are valid.
        test::check_queries_at_path(*language, &current_dir.join("queries"))?;

        // Run the syntax highlighting tests.
        let test_highlight_dir = test_dir.join("highlight");
        if test_highlight_dir.is_dir() {
            test_highlight::test_highlights(&loader, &test_highlight_dir)?;
        }
    } else if let Some(matches) = matches.subcommand_matches("parse") {
        let debug = matches.is_present("debug");
        let debug_graph = matches.is_present("debug-graph");
        let quiet = matches.is_present("quiet");
        let time = matches.is_present("time");
        let edits = matches
            .values_of("edits")
            .map_or(Vec::new(), |e| e.collect());
        let allow_cancellation = matches.is_present("allow-cancellation");
        let timeout = matches
            .value_of("timeout")
            .map_or(0, |t| u64::from_str_radix(t, 10).unwrap());
        let paths = collect_paths(matches.values_of("path").unwrap())?;
        let max_path_length = paths.iter().map(|p| p.chars().count()).max().unwrap();
        let mut has_error = false;
        loader.find_all_languages(&config.parser_directories)?;
        for path in paths {
            let path = Path::new(&path);
            let language =
                select_language(&mut loader, path, &current_dir, matches.value_of("scope"))?;
            has_error |= parse::parse_file_at_path(
                language,
                path,
                &edits,
                max_path_length,
                quiet,
                time,
                timeout,
                debug,
                debug_graph,
                allow_cancellation,
            )?;
        }
        if has_error {
            return Error::err(String::new());
        }
    } else if let Some(matches) = matches.subcommand_matches("query") {
        let ordered_captures = matches.values_of("captures").is_some();
        let paths = matches
            .values_of("path")
            .unwrap()
            .into_iter()
            .map(Path::new)
            .collect::<Vec<&Path>>();
        loader.find_all_languages(&config.parser_directories)?;
        let language = select_language(
            &mut loader,
            paths[0],
            &current_dir,
            matches.value_of("scope"),
        )?;
        let query_path = Path::new(matches.value_of("query-path").unwrap());
        query::query_files_at_paths(language, paths, query_path, ordered_captures)?;
    } else if let Some(matches) = matches.subcommand_matches("highlight") {
        loader.configure_highlights(&config.theme.highlight_names);
        loader.find_all_languages(&config.parser_directories)?;

        let time = matches.is_present("time");
        let paths = matches.values_of("path").unwrap().into_iter();
        let html_mode = matches.is_present("html");
        if html_mode {
            println!("{}", highlight::HTML_HEADER);
        }

        let language_config;
        if let Some(scope) = matches.value_of("scope") {
            language_config = loader.language_configuration_for_scope(scope)?;
            if language_config.is_none() {
                return Error::err(format!("Unknown scope '{}'", scope));
            }
        } else {
            language_config = None;
        }

        for path in paths {
            let path = Path::new(path);
            let (language, language_config) = match language_config {
                Some(v) => v,
                None => match loader.language_configuration_for_file_name(path)? {
                    Some(v) => v,
                    None => {
                        eprintln!("No language found for path {:?}", path);
                        continue;
                    }
                },
            };

            let source = fs::read(path)?;

            if let Some(highlight_config) = language_config.highlight_config(language)? {
                if html_mode {
                    highlight::html(&loader, &config.theme, &source, highlight_config, time)?;
                } else {
                    highlight::ansi(&loader, &config.theme, &source, highlight_config, time)?;
                }
            } else {
                return Error::err(format!("No syntax highlighting query found"));
            }
        }
    } else if let Some(matches) = matches.subcommand_matches("build-wasm") {
        let grammar_path = current_dir.join(matches.value_of("path").unwrap_or(""));
        wasm::compile_language_to_wasm(&grammar_path, matches.is_present("docker"))?;
    } else if matches.subcommand_matches("web-ui").is_some() {
        web_ui::serve(&current_dir);
    } else if matches.subcommand_matches("dump-languages").is_some() {
        loader.find_all_languages(&config.parser_directories)?;
        for (configuration, language_path) in loader.get_all_language_configurations() {
            println!(
                concat!(
                    "scope: {}\n",
                    "parser: {:?}\n",
                    "highlights: {:?}\n",
                    "file_types: {:?}\n",
                    "content_regex: {:?}\n",
                    "injection_regex: {:?}\n",
                ),
                configuration.scope.as_ref().unwrap_or(&String::new()),
                language_path,
                configuration.highlights_filenames,
                configuration.file_types,
                configuration.content_regex,
                configuration.injection_regex,
            );
        }
    }

    Ok(())
}

fn collect_paths<'a>(paths: impl Iterator<Item = &'a str>) -> error::Result<Vec<String>> {
    let mut result = Vec::new();

    let mut incorporate_path = |path: &str, positive| {
        if positive {
            result.push(path.to_string());
        } else {
            if let Some(index) = result.iter().position(|p| p == path) {
                result.remove(index);
            }
        }
    };

    for mut path in paths {
        let mut positive = true;
        if path.starts_with("!") {
            positive = false;
            path = path.trim_start_matches("!");
        }

        if Path::new(path).exists() {
            incorporate_path(path, positive);
        } else {
            for path in glob(path)? {
                if let Some(path) = path?.to_str() {
                    incorporate_path(path, positive);
                }
            }
        }
    }
    Ok(result)
}

fn select_language(
    loader: &mut loader::Loader,
    path: &Path,
    current_dir: &Path,
    scope: Option<&str>,
) -> Result<Language, Error> {
    if let Some(scope) = scope {
        if let Some(config) =
            loader
                .language_configuration_for_scope(scope)
                .map_err(Error::wrap(|| {
                    format!("Failed to load language for scope '{}'", scope)
                }))?
        {
            Ok(config.0)
        } else {
            return Error::err(format!("Unknown scope '{}'", scope));
        }
    } else if let Some((lang, _)) =
        loader
            .language_configuration_for_file_name(path)
            .map_err(Error::wrap(|| {
                format!(
                    "Failed to load language for file name {:?}",
                    path.file_name().unwrap()
                )
            }))?
    {
        Ok(lang)
    } else if let Some(lang) = loader
        .languages_at_path(&current_dir)
        .map_err(Error::wrap(|| {
            "Failed to load language in current directory"
        }))?
        .first()
        .cloned()
    {
        Ok(lang)
    } else {
        eprintln!("No language found");
        Error::err("No language found".to_string())
    }
}
<|endoftext|>


<commit_before>use std::f64::{MAX_VALUE, MIN_VALUE};
use geometry::Prim;
use raytracer::Ray;
use vec3::Vec3;

#[allow(dead_code)]
#[deriving(Clone)]
pub struct BBox {
    pub min: Vec3,
    pub max: Vec3
}

/// Given a bounding box and a point, compute and return a new BBox that
/// encompasses the point and the space the original box encompassed.
#[allow(dead_code)]
pub fn union_point(b: &BBox, p: &Vec3) -> BBox {
    BBox {
        min: Vec3 {
            x: b.min.x.min(p.x),
            y: b.min.y.min(p.y),
            z: b.min.z.min(p.z)
        },
        max: Vec3 {
            x: b.max.x.max(p.x),
            y: b.max.y.max(p.y),
            z: b.max.z.max(p.z)
        }
    }
}

/// Given two points, compute and return a new BBox that encompasses both points
#[allow(dead_code)]
pub fn union_points(p1: &Vec3, p2: &Vec3) -> BBox {
    BBox {
        min: Vec3 {
            x: p1.x.min(p2.x),
            y: p1.y.min(p2.y),
            z: p1.z.min(p2.z)
        },
        max: Vec3 {
            x: p1.x.max(p2.x),
            y: p1.y.max(p2.y),
            z: p1.z.max(p2.z)
        }
    }
}

/// Given two bounding boxes, compute and return a new BBox that encompasses
/// both spaces the original two boxes encompassed.
#[allow(dead_code)]
pub fn union_bbox(b1: &BBox, b2: &BBox) -> BBox {
    BBox {
        min: Vec3 {
            x: b1.min.x.min(b2.min.x),
            y: b1.min.y.min(b2.min.y),
            z: b1.min.z.min(b2.min.z)
        },
        max: Vec3 {
            x: b1.max.x.max(b2.max.x),
            y: b1.max.y.max(b2.max.y),
            z: b1.max.z.max(b2.max.z)
        }
    }
}

/// Given a vector of prims, compute and return a new BBox that encompasses
/// all finite prims (ie. not including planes) in that vector.
pub fn get_bounds_from_objects(prims: &Vec<Box<Prim+Send+Share>>) -> BBox {
    let mut max = Vec3 {x: MIN_VALUE, y: MIN_VALUE, z: MIN_VALUE};
    let mut min = Vec3 {x: MAX_VALUE, y: MAX_VALUE, z: MAX_VALUE};

    for prim in prims.iter() {
        match prim.bounding() {
            Some(bounding) => {
                min.x = min.x.min(bounding.min.x);
                min.y = min.y.min(bounding.min.y);
                min.z = min.z.min(bounding.min.z);

                max.x = max.x.max(bounding.max.x);
                max.y = max.y.max(bounding.max.y);
                max.z = max.z.max(bounding.max.z);
            }
            None => {}
        }
    }

    BBox {
        min: min,
        max: max
    }
}

impl BBox {
    #[allow(dead_code)]
    pub fn intersects(&self, ray: &Ray) -> bool {
        let o = ray.origin;
        let d = ray.direction.scale(-1.0);

        let tx1 = (self.min.x - o.x) / d.x;
        let ty1 = (self.min.y - o.y) / d.y;
        let tz1 = (self.min.z - o.z) / d.z;

        let tx2 = (self.max.x - o.x) / d.x;
        let ty2 = (self.max.y - o.y) / d.y;
        let tz2 = (self.max.z - o.z) / d.z;

        let tx_min = tx1.min(tx2);
        let ty_min = ty1.min(ty2);
        let tz_min = tz1.min(tz2);
        let tx_max = tx1.max(tx2);
        let ty_max = ty1.max(ty2);
        let tz_max = tz1.max(tz2);

        let t_min = tx_min.max(ty_min).max(tz_min);
        let t_max = tx_max.min(ty_max).min(tz_max);

        t_min < t_max
    }

    #[allow(dead_code)]
    pub fn overlaps(&self, other: &BBox) -> bool {
        let x = self.max.x >= other.min.x && self.min.x <= other.max.x;
        let y = self.max.y >= other.min.y && self.min.y <= other.max.y;
        let z = self.max.z >= other.min.z && self.min.z <= other.max.z;

        x && y && z
    }

    #[allow(dead_code)]
    pub fn inside(&self, p: &Vec3) -> bool {
        p.x >= self.min.x && p.x <= self.max.x &&
        p.y >= self.min.y && p.y <= self.max.y &&
        p.z >= self.min.z && p.z <= self.max.z
    }

    #[allow(dead_code)]
    pub fn contains(&self, other: &BBox) -> bool {
        !(other.min.x > self.max.x || other.max.x < self.min.x ||
          other.min.y > self.max.y || other.max.y < self.min.y ||
          other.min.z > self.max.z || other.max.z < self.min.z)
    }

    /// Pad bounding box by a constant factor.
    #[allow(dead_code)]
    pub fn expand(&self, delta: f64) -> BBox {
        let delta_vec3 = Vec3 {x: delta, y: delta, z: delta};

        BBox {
            min: self.min - delta_vec3,
            max: self.max - delta_vec3
        }
    }

    /// Returns which axis is the widest. 0: x, 1: y, 2: z
    #[allow(dead_code)]
    pub fn max_extent(&self) -> uint {
        let diag = self.max - self.min;
        if diag.x > diag.y && diag.x > diag.z {
            0
        } else if diag.y > diag.z {
            1
        } else {
            2
        }
    }

    /// Interpolate between corners of the box.
    #[allow(dead_code)]
    pub fn lerp(&self, t_x: f64, t_y: f64, t_z: f64) -> Vec3 {
        let diag = self.max - self.min;
        Vec3 {
            x: self.min.x + diag.x * t_x,
            y: self.min.y + diag.y * t_y,
            z: self.min.z + diag.z * t_z
        }
    }

    /// Offset from minimum corner point
    #[allow(dead_code)]
    pub fn offset(&self, offset: &Vec3) -> Vec3 {
        let diag = self.max - self.min;
        Vec3 {
            x: (offset.x - self.min.x) / diag.x,
            y: (offset.y - self.min.y) / diag.y,
            z: (offset.z - self.min.z) / diag.z
        }
    }

    #[allow(dead_code)]
    pub fn x_len(&self) -> f64 {
        self.max.x - self.min.x
    }

    #[allow(dead_code)]
    pub fn y_len(&self) -> f64 {
        self.max.y - self.min.y
    }

    #[allow(dead_code)]
    pub fn z_len(&self) -> f64 {
        self.max.z - self.min.z
    }

    #[allow(dead_code)]
    pub fn len(&self) -> Vec3 {
        self.max - self.min
    }
}
<commit_msg>Fix BBox::expand not expanding<commit_after>use std::f64::{MAX_VALUE, MIN_VALUE};
use geometry::Prim;
use raytracer::Ray;
use vec3::Vec3;

#[allow(dead_code)]
#[deriving(Clone)]
pub struct BBox {
    pub min: Vec3,
    pub max: Vec3
}

/// Given a bounding box and a point, compute and return a new BBox that
/// encompasses the point and the space the original box encompassed.
#[allow(dead_code)]
pub fn union_point(b: &BBox, p: &Vec3) -> BBox {
    BBox {
        min: Vec3 {
            x: b.min.x.min(p.x),
            y: b.min.y.min(p.y),
            z: b.min.z.min(p.z)
        },
        max: Vec3 {
            x: b.max.x.max(p.x),
            y: b.max.y.max(p.y),
            z: b.max.z.max(p.z)
        }
    }
}

/// Given two points, compute and return a new BBox that encompasses both points
#[allow(dead_code)]
pub fn union_points(p1: &Vec3, p2: &Vec3) -> BBox {
    BBox {
        min: Vec3 {
            x: p1.x.min(p2.x),
            y: p1.y.min(p2.y),
            z: p1.z.min(p2.z)
        },
        max: Vec3 {
            x: p1.x.max(p2.x),
            y: p1.y.max(p2.y),
            z: p1.z.max(p2.z)
        }
    }
}

/// Given two bounding boxes, compute and return a new BBox that encompasses
/// both spaces the original two boxes encompassed.
#[allow(dead_code)]
pub fn union_bbox(b1: &BBox, b2: &BBox) -> BBox {
    BBox {
        min: Vec3 {
            x: b1.min.x.min(b2.min.x),
            y: b1.min.y.min(b2.min.y),
            z: b1.min.z.min(b2.min.z)
        },
        max: Vec3 {
            x: b1.max.x.max(b2.max.x),
            y: b1.max.y.max(b2.max.y),
            z: b1.max.z.max(b2.max.z)
        }
    }
}

/// Given a vector of prims, compute and return a new BBox that encompasses
/// all finite prims (ie. not including planes) in that vector.
pub fn get_bounds_from_objects(prims: &Vec<Box<Prim+Send+Share>>) -> BBox {
    let mut max = Vec3 {x: MIN_VALUE, y: MIN_VALUE, z: MIN_VALUE};
    let mut min = Vec3 {x: MAX_VALUE, y: MAX_VALUE, z: MAX_VALUE};

    for prim in prims.iter() {
        match prim.bounding() {
            Some(bounding) => {
                min.x = min.x.min(bounding.min.x);
                min.y = min.y.min(bounding.min.y);
                min.z = min.z.min(bounding.min.z);

                max.x = max.x.max(bounding.max.x);
                max.y = max.y.max(bounding.max.y);
                max.z = max.z.max(bounding.max.z);
            }
            None => {}
        }
    }

    BBox {
        min: min,
        max: max
    }
}

impl BBox {
    #[allow(dead_code)]
    pub fn intersects(&self, ray: &Ray) -> bool {
        let o = ray.origin;
        let d = ray.direction.scale(-1.0);

        let tx1 = (self.min.x - o.x) / d.x;
        let ty1 = (self.min.y - o.y) / d.y;
        let tz1 = (self.min.z - o.z) / d.z;

        let tx2 = (self.max.x - o.x) / d.x;
        let ty2 = (self.max.y - o.y) / d.y;
        let tz2 = (self.max.z - o.z) / d.z;

        let tx_min = tx1.min(tx2);
        let ty_min = ty1.min(ty2);
        let tz_min = tz1.min(tz2);
        let tx_max = tx1.max(tx2);
        let ty_max = ty1.max(ty2);
        let tz_max = tz1.max(tz2);

        let t_min = tx_min.max(ty_min).max(tz_min);
        let t_max = tx_max.min(ty_max).min(tz_max);

        t_min < t_max
    }

    #[allow(dead_code)]
    pub fn overlaps(&self, other: &BBox) -> bool {
        let x = self.max.x >= other.min.x && self.min.x <= other.max.x;
        let y = self.max.y >= other.min.y && self.min.y <= other.max.y;
        let z = self.max.z >= other.min.z && self.min.z <= other.max.z;

        x && y && z
    }

    #[allow(dead_code)]
    pub fn inside(&self, p: &Vec3) -> bool {
        p.x >= self.min.x && p.x <= self.max.x &&
        p.y >= self.min.y && p.y <= self.max.y &&
        p.z >= self.min.z && p.z <= self.max.z
    }

    #[allow(dead_code)]
    pub fn contains(&self, other: &BBox) -> bool {
        !(other.min.x > self.max.x || other.max.x < self.min.x ||
          other.min.y > self.max.y || other.max.y < self.min.y ||
          other.min.z > self.max.z || other.max.z < self.min.z)
    }

    /// Pad bounding box by a constant factor.
    #[allow(dead_code)]
    pub fn expand(&self, delta: f64) -> BBox {
        let delta_vec3 = Vec3 {x: delta, y: delta, z: delta};

        BBox {
            min: self.min - delta_vec3,
            max: self.max + delta_vec3
        }
    }

    /// Returns which axis is the widest. 0: x, 1: y, 2: z
    #[allow(dead_code)]
    pub fn max_extent(&self) -> uint {
        let diag = self.max - self.min;
        if diag.x > diag.y && diag.x > diag.z {
            0
        } else if diag.y > diag.z {
            1
        } else {
            2
        }
    }

    /// Interpolate between corners of the box.
    #[allow(dead_code)]
    pub fn lerp(&self, t_x: f64, t_y: f64, t_z: f64) -> Vec3 {
        let diag = self.max - self.min;
        Vec3 {
            x: self.min.x + diag.x * t_x,
            y: self.min.y + diag.y * t_y,
            z: self.min.z + diag.z * t_z
        }
    }

    /// Offset from minimum corner point
    #[allow(dead_code)]
    pub fn offset(&self, offset: &Vec3) -> Vec3 {
        let diag = self.max - self.min;
        Vec3 {
            x: (offset.x - self.min.x) / diag.x,
            y: (offset.y - self.min.y) / diag.y,
            z: (offset.z - self.min.z) / diag.z
        }
    }

    #[allow(dead_code)]
    pub fn x_len(&self) -> f64 {
        self.max.x - self.min.x
    }

    #[allow(dead_code)]
    pub fn y_len(&self) -> f64 {
        self.max.y - self.min.y
    }

    #[allow(dead_code)]
    pub fn z_len(&self) -> f64 {
        self.max.z - self.min.z
    }

    #[allow(dead_code)]
    pub fn len(&self) -> Vec3 {
        self.max - self.min
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]
use std::{cmp, result, io};

quick_error! {
    #[derive(Debug)]
    pub enum Error {
        Io(err: io::Error) {
            from()
            cause(err)
            description(err.description())
        }
        Store(err: StorageError) {
            from()
            cause(err)
            description(err.description())
        }
        StepLocalMsg {
            description("raft: cannot step raft local message")
        }
        StepPeerNotFound {
            description("raft: cannot step as peer not found")
        }
    }
}

quick_error! {
    #[derive(Debug, PartialEq)]
    pub enum StorageError {
        Compacted {
            description("log compacted")
        }
        Unavailable {
            description("log unavailable")
        }
        SnapshotOutOfDate {
            description("snapshot out of date")
        }
    }
}

impl cmp::PartialEq for Error {
    fn eq(&self, other: &Error) -> bool {
        match (self, other) {
            (&Error::StepPeerNotFound, &Error::StepPeerNotFound) => true,
            (&Error::Store(ref e1), &Error::Store(ref e2)) => e1 == e2,
            (&Error::Io(ref e1), &Error::Io(ref e2)) => e1.kind() == e2.kind(),
            (&Error::StepLocalMsg, &Error::StepLocalMsg) => true,
            _ => false,
        }
    }
}

pub type Result<T> = result::Result<T, Error>;

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

    #[test]
    fn test_equal() {
        assert_eq!(Error::StepPeerNotFound, Error::StepPeerNotFound);
        assert!(Error::StepPeerNotFound != Error::Store(StorageError::Compacted));
        assert_eq!(Error::Store(StorageError::Compacted),
                   Error::Store(StorageError::Compacted));
        assert_eq!(Error::StepLocalMsg, Error::StepLocalMsg);
        assert_eq!(Error::from(io::Error::new(io::ErrorKind::Other, "oh no!")),
                   Error::from(io::Error::new(io::ErrorKind::Other, "oh yes!")));
    }
}
<commit_msg>raft: add other error types<commit_after>#![allow(dead_code)]
use std::{cmp, result, io};
use std::error;
use protobuf::error::ProtobufError;

quick_error! {
    #[derive(Debug)]
    pub enum Error {
        Io(err: io::Error) {
            from()
            cause(err)
            description(err.description())
        }
        Store(err: StorageError) {
            from()
            cause(err)
            description(err.description())
        }
        StepLocalMsg {
            description("raft: cannot step raft local message")
        }
        StepPeerNotFound {
            description("raft: cannot step as peer not found")
        }
        ConfigInvalid(desc: String) {
            description(desc)
        }
        Other(err: Box<error::Error + Sync + Send>) {
            cause(err.as_ref())
            description(err.description())
        }
    }
}

impl Error {
    pub fn other<T: error::Error + Sync + Send + 'static>(err: T) -> Error {
        Error::Other(Box::new(err))
    }
}

impl cmp::PartialEq for Error {
    fn eq(&self, other: &Error) -> bool {
        match (self, other) {
            (&Error::StepPeerNotFound, &Error::StepPeerNotFound) => true,
            (&Error::Store(ref e1), &Error::Store(ref e2)) => e1 == e2,
            (&Error::Io(ref e1), &Error::Io(ref e2)) => e1.kind() == e2.kind(),
            (&Error::StepLocalMsg, &Error::StepLocalMsg) => true,
            (&Error::ConfigInvalid(ref e1), &Error::ConfigInvalid(ref e2)) => e1 == e2,
            _ => false,
        }
    }
}

impl From<ProtobufError> for Error {
    fn from(e: ProtobufError) -> Error {
        Error::other(e)
    }
}

quick_error! {
    #[derive(Debug)]
    pub enum StorageError {
        Compacted {
            description("log compacted")
        }
        Unavailable {
            description("log unavailable")
        }
        SnapshotOutOfDate {
            description("snapshot out of date")
        }
        SnapshotTemporarilyUnavailable {
            description("snapshot is temporarily unavailable")
        }
        Other(err: Box<error::Error + Sync + Send>) {
            cause(err.as_ref())
            description(err.description())
        }
    }
}

impl StorageError {
    pub fn other<T: error::Error + Sync + Send + 'static>(err: T) -> StorageError {
        StorageError::Other(Box::new(err))
    }
}

impl cmp::PartialEq for StorageError {
    fn eq(&self, other: &StorageError) -> bool {
        match (self, other) {
            (&StorageError::Compacted, &StorageError::Compacted) => true,
            (&StorageError::Unavailable, &StorageError::Unavailable) => true,
            (&StorageError::SnapshotOutOfDate,
             &StorageError::SnapshotOutOfDate) => true,
            (&StorageError::SnapshotTemporarilyUnavailable,
             &StorageError::SnapshotTemporarilyUnavailable) => true,
            _ => false,
        }
    }
}

pub type Result<T> = result::Result<T, Error>;

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

    #[test]
    fn test_error_equal() {
        assert_eq!(Error::StepPeerNotFound, Error::StepPeerNotFound);
        assert!(Error::StepPeerNotFound != Error::Store(StorageError::Compacted));
        assert_eq!(Error::Store(StorageError::Compacted),
                   Error::Store(StorageError::Compacted));
        assert_eq!(Error::StepLocalMsg, Error::StepLocalMsg);
        assert_eq!(Error::from(io::Error::new(io::ErrorKind::Other, "oh no!")),
                   Error::from(io::Error::new(io::ErrorKind::Other, "oh yes!")));
    }

    #[test]
    fn test_storage_error_equal() {
        assert_eq!(StorageError::Compacted, StorageError::Compacted);
        assert!(StorageError::Compacted != StorageError::Unavailable);
        assert_eq!(StorageError::Unavailable, StorageError::Unavailable);
        assert_eq!(StorageError::SnapshotOutOfDate,
                   StorageError::SnapshotOutOfDate);
        assert_eq!(StorageError::SnapshotTemporarilyUnavailable,
                   StorageError::SnapshotTemporarilyUnavailable);
        assert!(StorageError::other(Error::StepLocalMsg) != StorageError::Unavailable);
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2020 Jason Ish
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

use std::path::PathBuf;

use rusqlite::OpenFlags;

pub mod configrepo;
pub mod eventstore;
pub mod importer;
pub mod init;
pub mod queryparser;
pub mod retention;

pub struct ConnectionBuilder {
    pub filename: Option<PathBuf>,
}

impl ConnectionBuilder {
    pub fn filename<T: Into<PathBuf>>(filename: Option<T>) -> ConnectionBuilder {
        ConnectionBuilder {
            filename: if let Some(filename) = filename {
                Some(filename.into())
            } else {
                None
            },
        }
    }

    pub fn open(&self) -> Result<rusqlite::Connection, rusqlite::Error> {
        let flags = OpenFlags::SQLITE_OPEN_READ_WRITE
            | OpenFlags::SQLITE_OPEN_CREATE
            | OpenFlags::SQLITE_OPEN_SHARED_CACHE
            | OpenFlags::SQLITE_OPEN_FULL_MUTEX;
        if let Some(filename) = &self.filename {
            let c = rusqlite::Connection::open_with_flags(&filename, flags)?;
            Ok(c)
        } else {
            rusqlite::Connection::open_in_memory()
        }
    }
}

pub fn init_event_db(db: &mut rusqlite::Connection) -> Result<(), rusqlite::Error> {
    crate::sqlite::init::init_db(db, "sqlite")?;
    Ok(())
}

/// Format a DateTime object into the SQLite format.
pub fn format_sqlite_timestamp(dt: &chrono::DateTime<chrono::Utc>) -> String {
    let dt = dt.with_timezone(&chrono::Utc);
    dt.format("%Y-%m-%dT%H:%M:%S.%6f%z").to_string()
}
<commit_msg>server: fixed logged database name when creating sqlite event store<commit_after>// Copyright (C) 2020 Jason Ish
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

use std::path::PathBuf;

use rusqlite::OpenFlags;

pub mod configrepo;
pub mod eventstore;
pub mod importer;
pub mod init;
pub mod queryparser;
pub mod retention;

pub struct ConnectionBuilder {
    pub filename: Option<PathBuf>,
}

impl ConnectionBuilder {
    pub fn filename<T: Into<PathBuf>>(filename: Option<T>) -> ConnectionBuilder {
        ConnectionBuilder {
            filename: if let Some(filename) = filename {
                Some(filename.into())
            } else {
                None
            },
        }
    }

    pub fn open(&self) -> Result<rusqlite::Connection, rusqlite::Error> {
        let flags = OpenFlags::SQLITE_OPEN_READ_WRITE
            | OpenFlags::SQLITE_OPEN_CREATE
            | OpenFlags::SQLITE_OPEN_SHARED_CACHE
            | OpenFlags::SQLITE_OPEN_FULL_MUTEX;
        if let Some(filename) = &self.filename {
            let c = rusqlite::Connection::open_with_flags(&filename, flags)?;
            Ok(c)
        } else {
            rusqlite::Connection::open_in_memory()
        }
    }
}

pub fn init_event_db(db: &mut rusqlite::Connection) -> Result<(), rusqlite::Error> {
    crate::sqlite::init::init_db(db, "events")
}

/// Format a DateTime object into the SQLite format.
pub fn format_sqlite_timestamp(dt: &chrono::DateTime<chrono::Utc>) -> String {
    let dt = dt.with_timezone(&chrono::Utc);
    dt.format("%Y-%m-%dT%H:%M:%S.%6f%z").to_string()
}
<|endoftext|>