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

use ruma_macros::{Event, EventContent};
use serde::{Deserialize, Deserializer, Serialize};
use serde_json::value::RawValue as RawJsonValue;

use crate::{
    events::{
        EventContent, MessageLikeEventType, MessageLikeUnsigned, Redact, RedactContent,
        RedactedUnsigned, RedactionDeHelper,
    },
    serde::from_raw_json_value,
    EventId, MilliSecondsSinceUnixEpoch, RoomId, UserId,
};

/// A possibly-redacted redaction event.
#[allow(clippy::exhaustive_enums)]
#[derive(Clone, Debug, Serialize)]
#[serde(untagged)]
pub enum RoomRedactionEvent {
    /// Original, unredacted form of the event.
    Original(OriginalRoomRedactionEvent),

    /// Redacted form of the event with minimal fields.
    Redacted(RedactedRoomRedactionEvent),
}

/// A possibly-redacted redaction event without a `room_id`.
#[allow(clippy::exhaustive_enums)]
#[derive(Clone, Debug, Serialize)]
#[serde(untagged)]
pub enum SyncRoomRedactionEvent {
    /// Original, unredacted form of the event.
    Original(OriginalSyncRoomRedactionEvent),

    /// Redacted form of the event with minimal fields.
    Redacted(RedactedSyncRoomRedactionEvent),
}

/// Redaction event.
#[derive(Clone, Debug, Event)]
#[allow(clippy::exhaustive_structs)]
pub struct OriginalRoomRedactionEvent {
    /// Data specific to the event type.
    pub content: RoomRedactionEventContent,

    /// The ID of the event that was redacted.
    pub redacts: Box<EventId>,

    /// The globally unique event identifier for the user who sent the event.
    pub event_id: Box<EventId>,

    /// The fully-qualified ID of the user who sent this event.
    pub sender: Box<UserId>,

    /// Timestamp in milliseconds on originating homeserver when this event was sent.
    pub origin_server_ts: MilliSecondsSinceUnixEpoch,

    /// The ID of the room associated with this event.
    pub room_id: Box<RoomId>,

    /// Additional key-value pairs not signed by the homeserver.
    pub unsigned: MessageLikeUnsigned,
}

impl Redact for OriginalRoomRedactionEvent {
    type Redacted = RedactedRoomRedactionEvent;

    fn redact(
        self,
        redaction: SyncRoomRedactionEvent,
        version: &crate::RoomVersionId,
    ) -> Self::Redacted {
        RedactedRoomRedactionEvent {
            content: self.content.redact(version),
            // There is no released room version where this isn't redacted yet
            redacts: None,
            event_id: self.event_id,
            sender: self.sender,
            origin_server_ts: self.origin_server_ts,
            room_id: self.room_id,
            unsigned: RedactedUnsigned::new_because(Box::new(redaction)),
        }
    }
}

/// Redacted redaction event.
#[derive(Clone, Debug, Event)]
#[allow(clippy::exhaustive_structs)]
pub struct RedactedRoomRedactionEvent {
    /// Data specific to the event type.
    pub content: RedactedRoomRedactionEventContent,

    /// The ID of the event that was redacted.
    pub redacts: Option<Box<EventId>>,

    /// The globally unique event identifier for the user who sent the event.
    pub event_id: Box<EventId>,

    /// The fully-qualified ID of the user who sent this event.
    pub sender: Box<UserId>,

    /// Timestamp in milliseconds on originating homeserver when this event was sent.
    pub origin_server_ts: MilliSecondsSinceUnixEpoch,

    /// The ID of the room associated with this event.
    pub room_id: Box<RoomId>,

    /// Additional key-value pairs not signed by the homeserver.
    pub unsigned: RedactedUnsigned,
}

/// Redaction event without a `room_id`.
#[derive(Clone, Debug, Event)]
#[allow(clippy::exhaustive_structs)]
pub struct OriginalSyncRoomRedactionEvent {
    /// Data specific to the event type.
    pub content: RoomRedactionEventContent,

    /// The ID of the event that was redacted.
    pub redacts: Box<EventId>,

    /// The globally unique event identifier for the user who sent the event.
    pub event_id: Box<EventId>,

    /// The fully-qualified ID of the user who sent this event.
    pub sender: Box<UserId>,

    /// Timestamp in milliseconds on originating homeserver when this event was sent.
    pub origin_server_ts: MilliSecondsSinceUnixEpoch,

    /// Additional key-value pairs not signed by the homeserver.
    pub unsigned: MessageLikeUnsigned,
}

impl Redact for OriginalSyncRoomRedactionEvent {
    type Redacted = RedactedSyncRoomRedactionEvent;

    fn redact(
        self,
        redaction: SyncRoomRedactionEvent,
        version: &crate::RoomVersionId,
    ) -> Self::Redacted {
        RedactedSyncRoomRedactionEvent {
            content: self.content.redact(version),
            // There is no released room version where this isn't redacted yet
            redacts: None,
            event_id: self.event_id,
            sender: self.sender,
            origin_server_ts: self.origin_server_ts,
            unsigned: RedactedUnsigned::new_because(Box::new(redaction)),
        }
    }
}

/// Redacted redaction event without a `room_id`.
#[derive(Clone, Debug, Event)]
#[allow(clippy::exhaustive_structs)]
pub struct RedactedSyncRoomRedactionEvent {
    /// Data specific to the event type.
    pub content: RedactedRoomRedactionEventContent,

    /// The ID of the event that was redacted.
    pub redacts: Option<Box<EventId>>,

    /// The globally unique event identifier for the user who sent the event.
    pub event_id: Box<EventId>,

    /// The fully-qualified ID of the user who sent this event.
    pub sender: Box<UserId>,

    /// Timestamp in milliseconds on originating homeserver when this event was sent.
    pub origin_server_ts: MilliSecondsSinceUnixEpoch,

    /// Additional key-value pairs not signed by the homeserver.
    pub unsigned: RedactedUnsigned,
}

/// A redaction of an event.
#[derive(Clone, Debug, Default, Deserialize, Serialize, EventContent)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[ruma_event(type = "m.room.redaction", kind = MessageLike)]
pub struct RoomRedactionEventContent {
    /// The reason for the redaction, if any.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub reason: Option<String>,
}

impl RoomRedactionEventContent {
    /// Creates an empty `RoomRedactionEventContent`.
    pub fn new() -> Self {
        Self::default()
    }

    /// Creates a new `RoomRedactionEventContent` with the given reason.
    pub fn with_reason(reason: String) -> Self {
        Self { reason: Some(reason) }
    }
}

impl RoomRedactionEvent {
    /// Returns the `type` of this event.
    pub fn event_type(&self) -> MessageLikeEventType {
        match self {
            Self::Original(ev) => ev.content.event_type(),
            Self::Redacted(ev) => ev.content.event_type(),
        }
    }

    /// Returns this event's `event_id` field.
    pub fn event_id(&self) -> &EventId {
        match self {
            Self::Original(ev) => &ev.event_id,
            Self::Redacted(ev) => &ev.event_id,
        }
    }

    /// Returns this event's `sender` field.
    pub fn sender(&self) -> &UserId {
        match self {
            Self::Original(ev) => &ev.sender,
            Self::Redacted(ev) => &ev.sender,
        }
    }

    /// Returns this event's `origin_server_ts` field.
    pub fn origin_server_ts(&self) -> &MilliSecondsSinceUnixEpoch {
        match self {
            Self::Original(ev) => &ev.origin_server_ts,
            Self::Redacted(ev) => &ev.origin_server_ts,
        }
    }

    /// Returns this event's `room_id` field.
    pub fn room_id(&self) -> &RoomId {
        match self {
            Self::Original(ev) => &ev.room_id,
            Self::Redacted(ev) => &ev.room_id,
        }
    }
}

impl Redact for RoomRedactionEvent {
    type Redacted = Self;

    fn redact(self, redaction: SyncRoomRedactionEvent, version: &crate::RoomVersionId) -> Self {
        match self {
            Self::Original(ev) => Self::Redacted(ev.redact(redaction, version)),
            Self::Redacted(ev) => Self::Redacted(ev),
        }
    }
}

impl<'de> Deserialize<'de> for RoomRedactionEvent {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        let json = Box::<RawJsonValue>::deserialize(deserializer)?;
        let RedactionDeHelper { unsigned } = from_raw_json_value(&json)?;

        if unsigned.and_then(|u| u.redacted_because).is_some() {
            Ok(Self::Redacted(from_raw_json_value(&json)?))
        } else {
            Ok(Self::Original(from_raw_json_value(&json)?))
        }
    }
}

impl SyncRoomRedactionEvent {
    /// Returns the `type` of this event.
    pub fn event_type(&self) -> MessageLikeEventType {
        match self {
            Self::Original(ev) => ev.content.event_type(),
            Self::Redacted(ev) => ev.content.event_type(),
        }
    }

    /// Returns this event's `event_id` field.
    pub fn event_id(&self) -> &EventId {
        match self {
            Self::Original(ev) => &ev.event_id,
            Self::Redacted(ev) => &ev.event_id,
        }
    }

    /// Returns this event's `sender` field.
    pub fn sender(&self) -> &UserId {
        match self {
            Self::Original(ev) => &ev.sender,
            Self::Redacted(ev) => &ev.sender,
        }
    }

    /// Returns this event's `origin_server_ts` field.
    pub fn origin_server_ts(&self) -> &MilliSecondsSinceUnixEpoch {
        match self {
            Self::Original(ev) => &ev.origin_server_ts,
            Self::Redacted(ev) => &ev.origin_server_ts,
        }
    }

    /// Convert this sync event into a full event (one with a `room_id` field).
    pub fn into_full_event(self, room_id: Box<RoomId>) -> RoomRedactionEvent {
        match self {
            Self::Original(ev) => RoomRedactionEvent::Original(ev.into_full_event(room_id)),
            Self::Redacted(ev) => RoomRedactionEvent::Redacted(ev.into_full_event(room_id)),
        }
    }
}

impl From<RoomRedactionEvent> for SyncRoomRedactionEvent {
    fn from(full: RoomRedactionEvent) -> Self {
        match full {
            RoomRedactionEvent::Original(ev) => Self::Original(ev.into()),
            RoomRedactionEvent::Redacted(ev) => Self::Redacted(ev.into()),
        }
    }
}

impl Redact for SyncRoomRedactionEvent {
    type Redacted = Self;

    fn redact(self, redaction: SyncRoomRedactionEvent, version: &crate::RoomVersionId) -> Self {
        match self {
            Self::Original(ev) => Self::Redacted(ev.redact(redaction, version)),
            Self::Redacted(ev) => Self::Redacted(ev),
        }
    }
}

impl<'de> Deserialize<'de> for SyncRoomRedactionEvent {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        let json = Box::<RawJsonValue>::deserialize(deserializer)?;
        let RedactionDeHelper { unsigned } = from_raw_json_value(&json)?;

        if unsigned.and_then(|u| u.redacted_because).is_some() {
            Ok(Self::Redacted(from_raw_json_value(&json)?))
        } else {
            Ok(Self::Original(from_raw_json_value(&json)?))
        }
    }
}
<commit_msg>events: Remove redacts field from redacted redaction events<commit_after>//! Types for the [`m.room.redaction`] event.
//!
//! [`m.room.redaction`]: https://spec.matrix.org/v1.2/client-server-api/#mroomredaction

use ruma_macros::{Event, EventContent};
use serde::{Deserialize, Deserializer, Serialize};
use serde_json::value::RawValue as RawJsonValue;

use crate::{
    events::{
        EventContent, MessageLikeEventType, MessageLikeUnsigned, Redact, RedactContent,
        RedactedUnsigned, RedactionDeHelper,
    },
    serde::from_raw_json_value,
    EventId, MilliSecondsSinceUnixEpoch, RoomId, UserId,
};

/// A possibly-redacted redaction event.
#[allow(clippy::exhaustive_enums)]
#[derive(Clone, Debug, Serialize)]
#[serde(untagged)]
pub enum RoomRedactionEvent {
    /// Original, unredacted form of the event.
    Original(OriginalRoomRedactionEvent),

    /// Redacted form of the event with minimal fields.
    Redacted(RedactedRoomRedactionEvent),
}

/// A possibly-redacted redaction event without a `room_id`.
#[allow(clippy::exhaustive_enums)]
#[derive(Clone, Debug, Serialize)]
#[serde(untagged)]
pub enum SyncRoomRedactionEvent {
    /// Original, unredacted form of the event.
    Original(OriginalSyncRoomRedactionEvent),

    /// Redacted form of the event with minimal fields.
    Redacted(RedactedSyncRoomRedactionEvent),
}

/// Redaction event.
#[derive(Clone, Debug, Event)]
#[allow(clippy::exhaustive_structs)]
pub struct OriginalRoomRedactionEvent {
    /// Data specific to the event type.
    pub content: RoomRedactionEventContent,

    /// The ID of the event that was redacted.
    pub redacts: Box<EventId>,

    /// The globally unique event identifier for the user who sent the event.
    pub event_id: Box<EventId>,

    /// The fully-qualified ID of the user who sent this event.
    pub sender: Box<UserId>,

    /// Timestamp in milliseconds on originating homeserver when this event was sent.
    pub origin_server_ts: MilliSecondsSinceUnixEpoch,

    /// The ID of the room associated with this event.
    pub room_id: Box<RoomId>,

    /// Additional key-value pairs not signed by the homeserver.
    pub unsigned: MessageLikeUnsigned,
}

impl Redact for OriginalRoomRedactionEvent {
    type Redacted = RedactedRoomRedactionEvent;

    fn redact(
        self,
        redaction: SyncRoomRedactionEvent,
        version: &crate::RoomVersionId,
    ) -> Self::Redacted {
        RedactedRoomRedactionEvent {
            content: self.content.redact(version),
            event_id: self.event_id,
            sender: self.sender,
            origin_server_ts: self.origin_server_ts,
            room_id: self.room_id,
            unsigned: RedactedUnsigned::new_because(Box::new(redaction)),
        }
    }
}

/// Redacted redaction event.
#[derive(Clone, Debug, Event)]
#[allow(clippy::exhaustive_structs)]
pub struct RedactedRoomRedactionEvent {
    /// Data specific to the event type.
    pub content: RedactedRoomRedactionEventContent,

    /// The globally unique event identifier for the user who sent the event.
    pub event_id: Box<EventId>,

    /// The fully-qualified ID of the user who sent this event.
    pub sender: Box<UserId>,

    /// Timestamp in milliseconds on originating homeserver when this event was sent.
    pub origin_server_ts: MilliSecondsSinceUnixEpoch,

    /// The ID of the room associated with this event.
    pub room_id: Box<RoomId>,

    /// Additional key-value pairs not signed by the homeserver.
    pub unsigned: RedactedUnsigned,
}

/// Redaction event without a `room_id`.
#[derive(Clone, Debug, Event)]
#[allow(clippy::exhaustive_structs)]
pub struct OriginalSyncRoomRedactionEvent {
    /// Data specific to the event type.
    pub content: RoomRedactionEventContent,

    /// The ID of the event that was redacted.
    pub redacts: Box<EventId>,

    /// The globally unique event identifier for the user who sent the event.
    pub event_id: Box<EventId>,

    /// The fully-qualified ID of the user who sent this event.
    pub sender: Box<UserId>,

    /// Timestamp in milliseconds on originating homeserver when this event was sent.
    pub origin_server_ts: MilliSecondsSinceUnixEpoch,

    /// Additional key-value pairs not signed by the homeserver.
    pub unsigned: MessageLikeUnsigned,
}

impl Redact for OriginalSyncRoomRedactionEvent {
    type Redacted = RedactedSyncRoomRedactionEvent;

    fn redact(
        self,
        redaction: SyncRoomRedactionEvent,
        version: &crate::RoomVersionId,
    ) -> Self::Redacted {
        RedactedSyncRoomRedactionEvent {
            content: self.content.redact(version),
            event_id: self.event_id,
            sender: self.sender,
            origin_server_ts: self.origin_server_ts,
            unsigned: RedactedUnsigned::new_because(Box::new(redaction)),
        }
    }
}

/// Redacted redaction event without a `room_id`.
#[derive(Clone, Debug, Event)]
#[allow(clippy::exhaustive_structs)]
pub struct RedactedSyncRoomRedactionEvent {
    /// Data specific to the event type.
    pub content: RedactedRoomRedactionEventContent,

    /// The globally unique event identifier for the user who sent the event.
    pub event_id: Box<EventId>,

    /// The fully-qualified ID of the user who sent this event.
    pub sender: Box<UserId>,

    /// Timestamp in milliseconds on originating homeserver when this event was sent.
    pub origin_server_ts: MilliSecondsSinceUnixEpoch,

    /// Additional key-value pairs not signed by the homeserver.
    pub unsigned: RedactedUnsigned,
}

/// A redaction of an event.
#[derive(Clone, Debug, Default, Deserialize, Serialize, EventContent)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[ruma_event(type = "m.room.redaction", kind = MessageLike)]
pub struct RoomRedactionEventContent {
    /// The reason for the redaction, if any.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub reason: Option<String>,
}

impl RoomRedactionEventContent {
    /// Creates an empty `RoomRedactionEventContent`.
    pub fn new() -> Self {
        Self::default()
    }

    /// Creates a new `RoomRedactionEventContent` with the given reason.
    pub fn with_reason(reason: String) -> Self {
        Self { reason: Some(reason) }
    }
}

impl RoomRedactionEvent {
    /// Returns the `type` of this event.
    pub fn event_type(&self) -> MessageLikeEventType {
        match self {
            Self::Original(ev) => ev.content.event_type(),
            Self::Redacted(ev) => ev.content.event_type(),
        }
    }

    /// Returns this event's `event_id` field.
    pub fn event_id(&self) -> &EventId {
        match self {
            Self::Original(ev) => &ev.event_id,
            Self::Redacted(ev) => &ev.event_id,
        }
    }

    /// Returns this event's `sender` field.
    pub fn sender(&self) -> &UserId {
        match self {
            Self::Original(ev) => &ev.sender,
            Self::Redacted(ev) => &ev.sender,
        }
    }

    /// Returns this event's `origin_server_ts` field.
    pub fn origin_server_ts(&self) -> &MilliSecondsSinceUnixEpoch {
        match self {
            Self::Original(ev) => &ev.origin_server_ts,
            Self::Redacted(ev) => &ev.origin_server_ts,
        }
    }

    /// Returns this event's `room_id` field.
    pub fn room_id(&self) -> &RoomId {
        match self {
            Self::Original(ev) => &ev.room_id,
            Self::Redacted(ev) => &ev.room_id,
        }
    }
}

impl Redact for RoomRedactionEvent {
    type Redacted = Self;

    fn redact(self, redaction: SyncRoomRedactionEvent, version: &crate::RoomVersionId) -> Self {
        match self {
            Self::Original(ev) => Self::Redacted(ev.redact(redaction, version)),
            Self::Redacted(ev) => Self::Redacted(ev),
        }
    }
}

impl<'de> Deserialize<'de> for RoomRedactionEvent {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        let json = Box::<RawJsonValue>::deserialize(deserializer)?;
        let RedactionDeHelper { unsigned } = from_raw_json_value(&json)?;

        if unsigned.and_then(|u| u.redacted_because).is_some() {
            Ok(Self::Redacted(from_raw_json_value(&json)?))
        } else {
            Ok(Self::Original(from_raw_json_value(&json)?))
        }
    }
}

impl SyncRoomRedactionEvent {
    /// Returns the `type` of this event.
    pub fn event_type(&self) -> MessageLikeEventType {
        match self {
            Self::Original(ev) => ev.content.event_type(),
            Self::Redacted(ev) => ev.content.event_type(),
        }
    }

    /// Returns this event's `event_id` field.
    pub fn event_id(&self) -> &EventId {
        match self {
            Self::Original(ev) => &ev.event_id,
            Self::Redacted(ev) => &ev.event_id,
        }
    }

    /// Returns this event's `sender` field.
    pub fn sender(&self) -> &UserId {
        match self {
            Self::Original(ev) => &ev.sender,
            Self::Redacted(ev) => &ev.sender,
        }
    }

    /// Returns this event's `origin_server_ts` field.
    pub fn origin_server_ts(&self) -> &MilliSecondsSinceUnixEpoch {
        match self {
            Self::Original(ev) => &ev.origin_server_ts,
            Self::Redacted(ev) => &ev.origin_server_ts,
        }
    }

    /// Convert this sync event into a full event (one with a `room_id` field).
    pub fn into_full_event(self, room_id: Box<RoomId>) -> RoomRedactionEvent {
        match self {
            Self::Original(ev) => RoomRedactionEvent::Original(ev.into_full_event(room_id)),
            Self::Redacted(ev) => RoomRedactionEvent::Redacted(ev.into_full_event(room_id)),
        }
    }
}

impl From<RoomRedactionEvent> for SyncRoomRedactionEvent {
    fn from(full: RoomRedactionEvent) -> Self {
        match full {
            RoomRedactionEvent::Original(ev) => Self::Original(ev.into()),
            RoomRedactionEvent::Redacted(ev) => Self::Redacted(ev.into()),
        }
    }
}

impl Redact for SyncRoomRedactionEvent {
    type Redacted = Self;

    fn redact(self, redaction: SyncRoomRedactionEvent, version: &crate::RoomVersionId) -> Self {
        match self {
            Self::Original(ev) => Self::Redacted(ev.redact(redaction, version)),
            Self::Redacted(ev) => Self::Redacted(ev),
        }
    }
}

impl<'de> Deserialize<'de> for SyncRoomRedactionEvent {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        let json = Box::<RawJsonValue>::deserialize(deserializer)?;
        let RedactionDeHelper { unsigned } = from_raw_json_value(&json)?;

        if unsigned.and_then(|u| u.redacted_because).is_some() {
            Ok(Self::Redacted(from_raw_json_value(&json)?))
        } else {
            Ok(Self::Original(from_raw_json_value(&json)?))
        }
    }
}
<|endoftext|>


<commit_before>use term::*;
use term::Term::*;
use term::Error::*;
use booleans::*;

// PAIR := λxyf.f x y
pub fn pair() -> Term { abs(abs(abs(Var(1).app(Var(3)).app(Var(2))))) }

// FIRST := λp.p TRUE
pub fn first() -> Term { abs(Var(1).app(tru())) }

// SECOND := λp.p FALSE
pub fn second() -> Term { abs(Var(1).app(fls())) }

// NIL := λx.TRUE
pub fn nil() -> Term { abs(tru()) }

// NULL := λp.p (λxy.FALSE)
pub fn null() -> Term { abs(Var(1).app(abs(abs(fls())))) }

// CONS := λht.PAIR FALSE (PAIR h t)
pub fn cons() -> Term { abs(abs(pair().app(fls()).app(pair().app(Var(2)).app(Var(1))))) }

// HEAD := λz.FIRST (SECOND z)
pub fn head() -> Term { abs(first().app(second().app(Var(1)))) }

// TAIL := λz.SECOND (SECOND z)
pub fn tail() -> Term { abs(second().app(second().app(Var(1)))) }

impl Term {
	pub fn is_pair(&self) -> bool {
		self.fst_ref().is_ok() && self.snd_ref().is_ok()
	}

	pub fn unpair(self) -> Result<(Term, Term), Error> {
		if let Abs(_) = self {
			if let Ok((wrapped_a, b)) = self.unabs().and_then(|t| t.unapp()) {
				Ok((try!(wrapped_a.rhs()), b))
			} else {
				Err(NotAPair)
			}
		} else {
			if let Ok((wrapped_a, b)) = self.unapp() {
				Ok((try!(wrapped_a.rhs()), b))
			} else {
				Err(NotAPair)
			}
		}
	}

	pub fn fst(self) -> Result<Term, Error> {
		if let Abs(_) = self {
			self.unabs()
				.and_then(|t| t.lhs())
				.and_then(|t| t.rhs())
		} else {
			self.lhs().and_then(|t| t.rhs())
		}
	}

	pub fn fst_ref(&self) -> Result<&Term, Error> {
		if let Abs(_) = *self {
			self.unabs_ref()
				.and_then(|t| t.lhs_ref())
				.and_then(|t| t.rhs_ref())
		} else {
			self.lhs_ref().and_then(|t| t.rhs_ref())
		}
	}

	pub fn fst_ref_mut(&mut self) -> Result<&mut Term, Error> {
		if let Abs(_) = *self {
			self.unabs_ref_mut()
				.and_then(|t| t.lhs_ref_mut())
				.and_then(|t| t.rhs_ref_mut())
		} else {
			self.lhs_ref_mut().and_then(|t| t.rhs_ref_mut())
		}
	}

	pub fn snd(self) -> Result<Term, Error> {
		if let Abs(_) = self {
			self.unabs().and_then(|t| t.rhs())
		} else {
			self.rhs()
		}
	}

	pub fn snd_ref(&self) -> Result<&Term, Error> {
		if let Abs(_) = *self {
			self.unabs_ref().and_then(|t| t.rhs_ref())
		} else {
			self.rhs_ref()
		}
	}

	pub fn snd_ref_mut(&mut self) -> Result<&mut Term, Error> {
		if let Abs(_) = *self {
			self.unabs_ref_mut().and_then(|t| t.rhs_ref_mut())
		} else {
			self.rhs_ref_mut()
		}
	}

	pub fn is_list(&self) -> bool {
		self.is_empty() || self.head_ref().is_ok() && self.tail_ref().is_ok()
	}

	pub fn is_empty(&self) -> bool {
		*self == nil()
	}

	pub fn uncons(self) -> Result<(Term, Term), Error> {
		self.unabs()
			.and_then(|t| t.snd())
			.and_then(|t| t.unpair())
	}

	pub fn head(self) -> Result<Term, Error> {
		self.unabs()
			.and_then(|t| t.snd())
			.and_then(|t| t.fst())
	}

	pub fn head_ref(&self) -> Result<&Term, Error> {
		self.unabs_ref()
			.and_then(|t| t.snd_ref())
			.and_then(|t| t.fst_ref())
	}

	pub fn head_ref_mut(&mut self) -> Result<&mut Term, Error> {
		self.unabs_ref_mut()
			.and_then(|t| t.snd_ref_mut())
			.and_then(|t| t.fst_ref_mut())
	}

	pub fn tail(self) -> Result<Term, Error> {
		self.unabs()
			.and_then(|t| t.snd())
			.and_then(|t| t.snd())
	}

	pub fn tail_ref(&self) -> Result<&Term, Error> {
		self.unabs_ref()
			.and_then(|t| t.snd_ref())
			.and_then(|t| t.snd_ref())
	}

	pub fn tail_ref_mut(&mut self) -> Result<&mut Term, Error> {
		self.unabs_ref_mut()
			.and_then(|t| t.snd_ref_mut())
			.and_then(|t| t.snd_ref_mut())
	}

	pub fn len(&self) -> Result<usize, Error> {
		let mut inner = self;
		let mut n = 0;

		while *inner != nil() {
			n += 1;
			inner = try!(inner.tail_ref());
		}

		Ok(n)
	}
}

/*
pub fn from(elems: Vec<Term>) -> List {
	let mut list = List::new();

	for elem in elems.into_iter().rev() { list.push(elem); }

	list
}

pub fn push(&mut self, term: Term) { // TODO: maybe no cloning?
	let tail = self.0.clone();
	*self = List(abs(app(Var(0), app(term, tail))))
}
*/
/*
impl Iterator for Term {
	type Item = Term;

	fn next(&mut self) -> Option<Term> {
		if self.is_empty() {
			None
		} else {
			self.pop()
		}
	}
}
*/
#[cfg(test)]
mod test {
	use super::*;
	use arithmetic::*;
	use reduction::*;

	#[test]
	fn empty_list() {
		let empty_list = nil();

		assert!(empty_list.is_list());
		assert!(empty_list.is_empty());
	}

	#[test]
	fn list_length() {
		let list0 = nil();
		assert_eq!(list0.len(), Ok(0));
		let list1 = normalize(cons().app(one()).app(list0));
		assert_eq!(list1.len(), Ok(1));
		let list2 = normalize(cons().app(one()).app(list1));
		assert_eq!(list2.len(), Ok(2));
		let list3 = normalize(cons().app(one()).app(list2));
		assert_eq!(list3.len(), Ok(3));
	}

	#[test]
	fn pair_operations() {
		let pair_four_three = normalize(pair().app(to_cnum(4)).app(to_cnum(3)));

		assert!(pair_four_three.is_pair());

		assert_eq!(pair_four_three.fst_ref(), Ok(&to_cnum(4)));
		assert_eq!(pair_four_three.snd_ref(), Ok(&to_cnum(3)));

		let unpaired = pair_four_three.unpair();
		assert_eq!(unpaired, Ok((to_cnum(4), to_cnum(3))));
	}

	#[test]
	fn list_operations() {
		let empty_list = nil();
		let list_four = cons().app(to_cnum(4)).app(empty_list);
		let list_five_four = cons().app(to_cnum(5)).app(list_four);
		let list_three_five_four = normalize(cons().app(to_cnum(3)).app(list_five_four));

		assert!(list_three_five_four.is_list());

		assert_eq!(list_three_five_four.head_ref(), Ok(&to_cnum(3)));
		assert_eq!(list_three_five_four.tail_ref(), Ok(&normalize(cons().app(to_cnum(5)).app(cons().app(to_cnum(4)).app(nil())))));

		assert_eq!(list_three_five_four.tail_ref().and_then(|t| t.head_ref()), Ok(&to_cnum(5)));
		assert_eq!(list_three_five_four.tail_ref().and_then(|t| t.head_ref()), Ok(&to_cnum(5)));
		assert_eq!(list_three_five_four.tail_ref().and_then(|t| t.tail_ref()).and_then(|t| t.head_ref()), Ok(&to_cnum(4)));

		let unconsed = list_three_five_four.uncons();
		assert_eq!(unconsed, Ok((to_cnum(3), normalize(cons().app(to_cnum(5)).app(cons().app(to_cnum(4)).app(nil()))))));
	}

/*
	#[test]
	fn list_push_pop() {
		let mut list = List::from(vec![Var(1), Var(0), Var(1)]);

		assert_eq!(list.pop(), Some(Var(1)));
		assert_eq!(list.pop(), Some(Var(0)));
		assert_eq!(list.pop(), Some(Var(1)));
		assert_eq!(list.pop(), None);
	}

	#[test]
	fn iterating_list() {
		let list = List::from(vec![Var(0), Var(1), Var(0)]);
		let mut iter = list.into_iter();

		assert_eq!(iter.next(), Some(Var(0)));
		assert_eq!(iter.next(), Some(Var(1)));
		assert_eq!(iter.next(), Some(Var(0)));
	}
*/
}<commit_msg>impl From<Vec<Term>> for Term<commit_after>use term::*;
use term::Term::*;
use term::Error::*;
use booleans::*;
use reduction::*;

// PAIR := λxyf.f x y
pub fn pair() -> Term { abs(abs(abs(Var(1).app(Var(3)).app(Var(2))))) }

// FIRST := λp.p TRUE
pub fn first() -> Term { abs(Var(1).app(tru())) }

// SECOND := λp.p FALSE
pub fn second() -> Term { abs(Var(1).app(fls())) }

// NIL := λx.TRUE
pub fn nil() -> Term { abs(tru()) }

// NULL := λp.p (λxy.FALSE)
pub fn null() -> Term { abs(Var(1).app(abs(abs(fls())))) }

// CONS := λht.PAIR FALSE (PAIR h t)
pub fn cons() -> Term { abs(abs(pair().app(fls()).app(pair().app(Var(2)).app(Var(1))))) }

// HEAD := λz.FIRST (SECOND z)
pub fn head() -> Term { abs(first().app(second().app(Var(1)))) }

// TAIL := λz.SECOND (SECOND z)
pub fn tail() -> Term { abs(second().app(second().app(Var(1)))) }

impl Term {
	pub fn is_pair(&self) -> bool {
		self.fst_ref().is_ok() && self.snd_ref().is_ok()
	}

	pub fn unpair(self) -> Result<(Term, Term), Error> {
		if let Abs(_) = self {
			if let Ok((wrapped_a, b)) = self.unabs().and_then(|t| t.unapp()) {
				Ok((try!(wrapped_a.rhs()), b))
			} else {
				Err(NotAPair)
			}
		} else {
			if let Ok((wrapped_a, b)) = self.unapp() {
				Ok((try!(wrapped_a.rhs()), b))
			} else {
				Err(NotAPair)
			}
		}
	}

	pub fn fst(self) -> Result<Term, Error> {
		if let Abs(_) = self {
			self.unabs()
				.and_then(|t| t.lhs())
				.and_then(|t| t.rhs())
		} else {
			self.lhs().and_then(|t| t.rhs())
		}
	}

	pub fn fst_ref(&self) -> Result<&Term, Error> {
		if let Abs(_) = *self {
			self.unabs_ref()
				.and_then(|t| t.lhs_ref())
				.and_then(|t| t.rhs_ref())
		} else {
			self.lhs_ref().and_then(|t| t.rhs_ref())
		}
	}

	pub fn fst_ref_mut(&mut self) -> Result<&mut Term, Error> {
		if let Abs(_) = *self {
			self.unabs_ref_mut()
				.and_then(|t| t.lhs_ref_mut())
				.and_then(|t| t.rhs_ref_mut())
		} else {
			self.lhs_ref_mut().and_then(|t| t.rhs_ref_mut())
		}
	}

	pub fn snd(self) -> Result<Term, Error> {
		if let Abs(_) = self {
			self.unabs().and_then(|t| t.rhs())
		} else {
			self.rhs()
		}
	}

	pub fn snd_ref(&self) -> Result<&Term, Error> {
		if let Abs(_) = *self {
			self.unabs_ref().and_then(|t| t.rhs_ref())
		} else {
			self.rhs_ref()
		}
	}

	pub fn snd_ref_mut(&mut self) -> Result<&mut Term, Error> {
		if let Abs(_) = *self {
			self.unabs_ref_mut().and_then(|t| t.rhs_ref_mut())
		} else {
			self.rhs_ref_mut()
		}
	}

	pub fn is_list(&self) -> bool {
		self.is_empty() || self.head_ref().is_ok() && self.tail_ref().is_ok()
	}

	pub fn is_empty(&self) -> bool {
		*self == nil()
	}

	pub fn uncons(self) -> Result<(Term, Term), Error> {
		self.unabs()
			.and_then(|t| t.snd())
			.and_then(|t| t.unpair())
	}

	pub fn head(self) -> Result<Term, Error> {
		self.unabs()
			.and_then(|t| t.snd())
			.and_then(|t| t.fst())
	}

	pub fn head_ref(&self) -> Result<&Term, Error> {
		self.unabs_ref()
			.and_then(|t| t.snd_ref())
			.and_then(|t| t.fst_ref())
	}

	pub fn head_ref_mut(&mut self) -> Result<&mut Term, Error> {
		self.unabs_ref_mut()
			.and_then(|t| t.snd_ref_mut())
			.and_then(|t| t.fst_ref_mut())
	}

	pub fn tail(self) -> Result<Term, Error> {
		self.unabs()
			.and_then(|t| t.snd())
			.and_then(|t| t.snd())
	}

	pub fn tail_ref(&self) -> Result<&Term, Error> {
		self.unabs_ref()
			.and_then(|t| t.snd_ref())
			.and_then(|t| t.snd_ref())
	}

	pub fn tail_ref_mut(&mut self) -> Result<&mut Term, Error> {
		self.unabs_ref_mut()
			.and_then(|t| t.snd_ref_mut())
			.and_then(|t| t.snd_ref_mut())
	}

	pub fn len(&self) -> Result<usize, Error> {
		let mut inner = self;
		let mut n = 0;

		while *inner != nil() {
			n += 1;
			inner = try!(inner.tail_ref());
		}

		Ok(n)
	}
}

impl From<Vec<Term>> for Term {
	fn from(terms: Vec<Term>) -> Self {
		let mut output = nil();

		for t in terms {
			output = cons().app(t).app(output);
		}

		normalize(output)
	}
}
/*
pub fn push(&mut self, term: Term) { // TODO: maybe no cloning?
	let tail = self.0.clone();
	*self = List(abs(app(Var(0), app(term, tail))))
}
*/
/*
impl Iterator for Term {
	type Item = Term;

	fn next(&mut self) -> Option<Term> {
		if self.is_empty() {
			None
		} else {
			self.pop()
		}
	}
}
*/
#[cfg(test)]
mod test {
	use super::*;
	use arithmetic::*;

	#[test]
	fn empty_list() {
		let empty_list = nil();

		assert!(empty_list.is_list());
		assert!(empty_list.is_empty());
	}

	#[test]
	fn list_length() {
		let list0 = nil();
		assert_eq!(list0.len(), Ok(0));
		let list1 = normalize(cons().app(one()).app(list0));
		assert_eq!(list1.len(), Ok(1));
		let list2 = normalize(cons().app(one()).app(list1));
		assert_eq!(list2.len(), Ok(2));
		let list3 = normalize(cons().app(one()).app(list2));
		assert_eq!(list3.len(), Ok(3));
	}

	#[test]
	fn list_from_vector() {
		let terms_vec = vec![one(), zero(), one()];
		let list_from_vec = Term::from(terms_vec);
		let list_manual = normalize(cons().app(one()).app(cons().app(zero()).app(cons().app(one()).app(nil()))));

		assert_eq!(list_from_vec, list_manual);
	}

	#[test]
	fn pair_operations() {
		let pair_four_three = normalize(pair().app(to_cnum(4)).app(to_cnum(3)));

		assert!(pair_four_three.is_pair());

		assert_eq!(pair_four_three.fst_ref(), Ok(&to_cnum(4)));
		assert_eq!(pair_four_three.snd_ref(), Ok(&to_cnum(3)));

		let unpaired = pair_four_three.unpair();
		assert_eq!(unpaired, Ok((to_cnum(4), to_cnum(3))));
	}

	#[test]
	fn list_operations() {
		let empty_list = nil();
		let list_four = cons().app(to_cnum(4)).app(empty_list);
		let list_five_four = cons().app(to_cnum(5)).app(list_four);
		let list_three_five_four = normalize(cons().app(to_cnum(3)).app(list_five_four));

		assert!(list_three_five_four.is_list());

		assert_eq!(list_three_five_four.head_ref(), Ok(&to_cnum(3)));
		assert_eq!(list_three_five_four.tail_ref(), Ok(&normalize(cons().app(to_cnum(5)).app(cons().app(to_cnum(4)).app(nil())))));

		assert_eq!(list_three_five_four.tail_ref().and_then(|t| t.head_ref()), Ok(&to_cnum(5)));
		assert_eq!(list_three_five_four.tail_ref().and_then(|t| t.head_ref()), Ok(&to_cnum(5)));
		assert_eq!(list_three_five_four.tail_ref().and_then(|t| t.tail_ref()).and_then(|t| t.head_ref()), Ok(&to_cnum(4)));

		let unconsed = list_three_five_four.uncons();
		assert_eq!(unconsed, Ok((to_cnum(3), normalize(cons().app(to_cnum(5)).app(cons().app(to_cnum(4)).app(nil()))))));
	}

/*
	#[test]
	fn list_push_pop() {
		let mut list = List::from(vec![Var(1), Var(0), Var(1)]);

		assert_eq!(list.pop(), Some(Var(1)));
		assert_eq!(list.pop(), Some(Var(0)));
		assert_eq!(list.pop(), Some(Var(1)));
		assert_eq!(list.pop(), None);
	}

	#[test]
	fn iterating_list() {
		let list = List::from(vec![Var(0), Var(1), Var(0)]);
		let mut iter = list.into_iter();

		assert_eq!(iter.next(), Some(Var(0)));
		assert_eq!(iter.next(), Some(Var(1)));
		assert_eq!(iter.next(), Some(Var(0)));
	}
*/
}<|endoftext|>


<commit_before>#[macro_use(crate_version, crate_authors)]
extern crate clap;

use clap::{App, Arg};

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

fn main() {

    let matches = App::new("aux2bib")
                        .version(crate_version!())
                        .author(crate_authors!(",\n"))
                        .about("gets BibTeX keys from Inspire")
                        .arg(Arg::with_name("INPUT")
                             .help("Sets the input file to use")
                             .index(1))
                        .arg(Arg::with_name("OUTPUT")
                            .help("Sets the output file to use")
                            .index(2))
                        .get_matches();

    // Get input from specified file or stdin
    let mut input_data = String::new();

    match matches.value_of("INPUT") {
        Some(input_file_name) => {
            println!("Reading from file: {}", input_file_name);

            let f = File::open(input_file_name).expect("File not found");
            let mut reader = BufReader::new(f);
            reader.read_to_string(&mut input_data).unwrap();
        },
        None => {
            println!("Reading from stdin");

            let stdin = std::io::stdin();
            let stdin = stdin.lock();

            let mut reader = BufReader::new(stdin);
            reader.read_to_string(&mut input_data).unwrap();
        }
    }
}
<commit_msg>Add layout for rest of aux2bib's structure<commit_after>#[macro_use(crate_version, crate_authors)]
extern crate clap;

use clap::{App, Arg};

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

fn main() {

    // Define CLI
    let matches = App::new("aux2bib")
                        .version(crate_version!())
                        .author(crate_authors!(",\n"))
                        .about("gets BibTeX keys from Inspire")
                        .arg(Arg::with_name("INPUT")
                             .help("Sets the input file to use")
                             .index(1))
                        .arg(Arg::with_name("OUTPUT")
                            .help("Sets the output file to use")
                            .index(2))
                        .get_matches();

    // Get input from specified file or stdin
    let mut input_data = String::new();

    match matches.value_of("INPUT") {
        Some(input_file_name) => {
            println!("Reading from file: {}", input_file_name);

            let f = File::open(input_file_name).expect("File not found");
            let mut reader = BufReader::new(f);
            reader.read_to_string(&mut input_data).unwrap();
        },
        None => {
            println!("Reading from stdin");

            let stdin = std::io::stdin();
            let stdin = stdin.lock();

            let mut reader = BufReader::new(stdin);
            reader.read_to_string(&mut input_data).unwrap();
        }
    }

    // Extract BibTeX tags from document

    // Retrieve BibTeX entries from inspire.net

    // Write BibTeX entries to file or stdout
    match matches.value_of("OUTPUT") {
        Some(output_file_name) => {
            println!("Writing to file: {}", output_file_name);
        },
        None => {
            println!("Writing to stdout");
        }
    }
}
<|endoftext|>


<commit_before>use crate::utils::{
    get_trait_def_id, if_sequence, implements_trait, parent_node_is_if_expr, paths, span_lint_and_help, SpanlessEq,
};
use rustc_hir::{BinOpKind, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};

declare_clippy_lint! {
    /// **What it does:** Checks comparison chains written with `if` that can be
    /// rewritten with `match` and `cmp`.
    ///
    /// **Why is this bad?** `if` is not guaranteed to be exhaustive and conditionals can get
    /// repetitive
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust,ignore
    /// # fn a() {}
    /// # fn b() {}
    /// # fn c() {}
    /// fn f(x: u8, y: u8) {
    ///     if x > y {
    ///         a()
    ///     } else if x < y {
    ///         b()
    ///     } else {
    ///         c()
    ///     }
    /// }
    /// ```
    ///
    /// Could be written:
    ///
    /// ```rust,ignore
    /// use std::cmp::Ordering;
    /// # fn a() {}
    /// # fn b() {}
    /// # fn c() {}
    /// fn f(x: u8, y: u8) {
    ///      match x.cmp(&y) {
    ///          Ordering::Greater => a(),
    ///          Ordering::Less => b(),
    ///          Ordering::Equal => c()
    ///      }
    /// }
    /// ```
    pub COMPARISON_CHAIN,
    style,
    "`if`s that can be rewritten with `match` and `cmp`"
}

declare_lint_pass!(ComparisonChain => [COMPARISON_CHAIN]);

impl<'tcx> LateLintPass<'tcx> for ComparisonChain {
    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
        if expr.span.from_expansion() {
            return;
        }

        // We only care about the top-most `if` in the chain
        if parent_node_is_if_expr(expr, cx) {
            return;
        }

        // Check that there exists at least one explicit else condition
        let (conds, _) = if_sequence(expr);
        if conds.len() < 2 {
            return;
        }

        for cond in conds.windows(2) {
            if let (
                &ExprKind::Binary(ref kind1, ref lhs1, ref rhs1),
                &ExprKind::Binary(ref kind2, ref lhs2, ref rhs2),
            ) = (&cond[0].kind, &cond[1].kind)
            {
                if !kind_is_cmp(kind1.node) || !kind_is_cmp(kind2.node) {
                    return;
                }

                // Check that both sets of operands are equal
                let mut spanless_eq = SpanlessEq::new(cx);
                let same_fixed_operands = spanless_eq.eq_expr(lhs1, lhs2) && spanless_eq.eq_expr(rhs1, rhs2);
                let same_transposed_operands = spanless_eq.eq_expr(lhs1, rhs2) && spanless_eq.eq_expr(rhs1, lhs2);

                if !same_fixed_operands && !same_transposed_operands {
                    return;
                }

                // Check that if the operation is the same, either it's not `==` or the operands are transposed
                if kind1.node == kind2.node {
                    if kind1.node == BinOpKind::Eq {
                        return;
                    }
                    if !same_transposed_operands {
                        return;
                    }
                }

                // Check that the type being compared implements `core::cmp::Ord`
                let ty = cx.typeck_results().expr_ty(lhs1);
                let is_ord = get_trait_def_id(cx, &paths::ORD).map_or(false, |id| implements_trait(cx, ty, id, &[]));

                if !is_ord {
                    return;
                }
            } else {
                // We only care about comparison chains
                return;
            }
        }
        span_lint_and_help(
            cx,
            COMPARISON_CHAIN,
            expr.span,
            "`if` chain can be rewritten with `match`",
            None,
            "Consider rewriting the `if` chain to use `cmp` and `match`.",
        )
    }
}

fn kind_is_cmp(kind: BinOpKind) -> bool {
    matches!(kind, BinOpKind::Lt | BinOpKind::Gt | BinOpKind::Eq)
}
<commit_msg>Added known problem to comparison_chain docs<commit_after>use crate::utils::{
    get_trait_def_id, if_sequence, implements_trait, parent_node_is_if_expr, paths, span_lint_and_help, SpanlessEq,
};
use rustc_hir::{BinOpKind, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};

declare_clippy_lint! {
    /// **What it does:** Checks comparison chains written with `if` that can be
    /// rewritten with `match` and `cmp`.
    ///
    /// **Why is this bad?** `if` is not guaranteed to be exhaustive and conditionals can get
    /// repetitive
    ///
    /// **Known problems:** The match statement may be slower due to the compiler
    /// not inlining the call to cmp. See issue #5354
    ///
    /// **Example:**
    /// ```rust,ignore
    /// # fn a() {}
    /// # fn b() {}
    /// # fn c() {}
    /// fn f(x: u8, y: u8) {
    ///     if x > y {
    ///         a()
    ///     } else if x < y {
    ///         b()
    ///     } else {
    ///         c()
    ///     }
    /// }
    /// ```
    ///
    /// Could be written:
    ///
    /// ```rust,ignore
    /// use std::cmp::Ordering;
    /// # fn a() {}
    /// # fn b() {}
    /// # fn c() {}
    /// fn f(x: u8, y: u8) {
    ///      match x.cmp(&y) {
    ///          Ordering::Greater => a(),
    ///          Ordering::Less => b(),
    ///          Ordering::Equal => c()
    ///      }
    /// }
    /// ```
    pub COMPARISON_CHAIN,
    style,
    "`if`s that can be rewritten with `match` and `cmp`"
}

declare_lint_pass!(ComparisonChain => [COMPARISON_CHAIN]);

impl<'tcx> LateLintPass<'tcx> for ComparisonChain {
    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
        if expr.span.from_expansion() {
            return;
        }

        // We only care about the top-most `if` in the chain
        if parent_node_is_if_expr(expr, cx) {
            return;
        }

        // Check that there exists at least one explicit else condition
        let (conds, _) = if_sequence(expr);
        if conds.len() < 2 {
            return;
        }

        for cond in conds.windows(2) {
            if let (
                &ExprKind::Binary(ref kind1, ref lhs1, ref rhs1),
                &ExprKind::Binary(ref kind2, ref lhs2, ref rhs2),
            ) = (&cond[0].kind, &cond[1].kind)
            {
                if !kind_is_cmp(kind1.node) || !kind_is_cmp(kind2.node) {
                    return;
                }

                // Check that both sets of operands are equal
                let mut spanless_eq = SpanlessEq::new(cx);
                let same_fixed_operands = spanless_eq.eq_expr(lhs1, lhs2) && spanless_eq.eq_expr(rhs1, rhs2);
                let same_transposed_operands = spanless_eq.eq_expr(lhs1, rhs2) && spanless_eq.eq_expr(rhs1, lhs2);

                if !same_fixed_operands && !same_transposed_operands {
                    return;
                }

                // Check that if the operation is the same, either it's not `==` or the operands are transposed
                if kind1.node == kind2.node {
                    if kind1.node == BinOpKind::Eq {
                        return;
                    }
                    if !same_transposed_operands {
                        return;
                    }
                }

                // Check that the type being compared implements `core::cmp::Ord`
                let ty = cx.typeck_results().expr_ty(lhs1);
                let is_ord = get_trait_def_id(cx, &paths::ORD).map_or(false, |id| implements_trait(cx, ty, id, &[]));

                if !is_ord {
                    return;
                }
            } else {
                // We only care about comparison chains
                return;
            }
        }
        span_lint_and_help(
            cx,
            COMPARISON_CHAIN,
            expr.span,
            "`if` chain can be rewritten with `match`",
            None,
            "Consider rewriting the `if` chain to use `cmp` and `match`.",
        )
    }
}

fn kind_is_cmp(kind: BinOpKind) -> bool {
    matches!(kind, BinOpKind::Lt | BinOpKind::Gt | BinOpKind::Eq)
}
<|endoftext|>


<commit_before>use super::*;
use core::num::NonZeroUsize;
use ethereum_types::{H256, U128, U256};

macro_rules! impl_encodable_for_uint {
    ($type: ident, $bit_size: expr) => {
        impl Encode for $type {
            fn is_ssz_fixed_len() -> bool {
                true
            }

            fn ssz_fixed_len() -> usize {
                $bit_size / 8
            }

            fn ssz_append(&self, buf: &mut Vec<u8>) {
                buf.extend_from_slice(&self.to_le_bytes());
            }
        }
    };
}

impl_encodable_for_uint!(u8, 8);
impl_encodable_for_uint!(u16, 16);
impl_encodable_for_uint!(u32, 32);
impl_encodable_for_uint!(u64, 64);
impl_encodable_for_uint!(usize, 64);

/// The SSZ "union" type.
impl<T: Encode> Encode for Option<T> {
    fn is_ssz_fixed_len() -> bool {
        false
    }

    fn ssz_append(&self, buf: &mut Vec<u8>) {
        match self {
            None => buf.append(&mut encode_union_index(0)),
            Some(t) => {
                buf.append(&mut encode_union_index(1));
                t.ssz_append(buf);
            }
        }
    }
}

impl<T: Encode> Encode for Vec<T> {
    fn is_ssz_fixed_len() -> bool {
        false
    }

    fn ssz_append(&self, buf: &mut Vec<u8>) {
        if T::is_ssz_fixed_len() {
            buf.reserve(T::ssz_fixed_len() * self.len());

            for item in self {
                item.ssz_append(buf);
            }
        } else {
            let mut encoder = SszEncoder::list(buf, self.len() * BYTES_PER_LENGTH_OFFSET);

            for item in self {
                encoder.append(item);
            }

            encoder.finalize();
        }
    }
}

impl Encode for bool {
    fn is_ssz_fixed_len() -> bool {
        true
    }

    fn ssz_fixed_len() -> usize {
        1
    }

    fn ssz_append(&self, buf: &mut Vec<u8>) {
        buf.extend_from_slice(&(*self as u8).to_le_bytes());
    }
}

impl Encode for NonZeroUsize {
    fn is_ssz_fixed_len() -> bool {
        <usize as Encode>::is_ssz_fixed_len()
    }

    fn ssz_fixed_len() -> usize {
        <usize as Encode>::ssz_fixed_len()
    }

    fn ssz_append(&self, buf: &mut Vec<u8>) {
        self.get().ssz_append(buf)
    }
}

impl Encode for H256 {
    fn is_ssz_fixed_len() -> bool {
        true
    }

    fn ssz_fixed_len() -> usize {
        32
    }

    fn ssz_append(&self, buf: &mut Vec<u8>) {
        buf.extend_from_slice(self.as_bytes());
    }
}

impl Encode for U256 {
    fn is_ssz_fixed_len() -> bool {
        true
    }

    fn ssz_fixed_len() -> usize {
        32
    }

    fn ssz_append(&self, buf: &mut Vec<u8>) {
        let n = <Self as Encode>::ssz_fixed_len();
        let s = buf.len();

        buf.resize(s + n, 0);
        self.to_little_endian(&mut buf[s..]);
    }
}

impl Encode for U128 {
    fn is_ssz_fixed_len() -> bool {
        true
    }

    fn ssz_fixed_len() -> usize {
        16
    }

    fn ssz_append(&self, buf: &mut Vec<u8>) {
        let n = <Self as Encode>::ssz_fixed_len();
        let s = buf.len();

        buf.resize(s + n, 0);
        self.to_little_endian(&mut buf[s..]);
    }
}

macro_rules! impl_encodable_for_u8_array {
    ($len: expr) => {
        impl Encode for [u8; $len] {
            fn is_ssz_fixed_len() -> bool {
                true
            }

            fn ssz_fixed_len() -> usize {
                $len
            }

            fn ssz_append(&self, buf: &mut Vec<u8>) {
                buf.extend_from_slice(&self[..]);
            }
        }
    };
}

impl_encodable_for_u8_array!(4);
impl_encodable_for_u8_array!(32);

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

    #[test]
    fn vec_of_u8() {
        let vec: Vec<u8> = vec![];
        assert_eq!(vec.as_ssz_bytes(), vec![]);

        let vec: Vec<u8> = vec![1];
        assert_eq!(vec.as_ssz_bytes(), vec![1]);

        let vec: Vec<u8> = vec![0, 1, 2, 3];
        assert_eq!(vec.as_ssz_bytes(), vec![0, 1, 2, 3]);
    }

    #[test]
    fn vec_of_vec_of_u8() {
        let vec: Vec<Vec<u8>> = vec![];
        assert_eq!(vec.as_ssz_bytes(), vec![]);

        let vec: Vec<Vec<u8>> = vec![vec![]];
        assert_eq!(vec.as_ssz_bytes(), vec![4, 0, 0, 0]);

        let vec: Vec<Vec<u8>> = vec![vec![], vec![]];
        assert_eq!(vec.as_ssz_bytes(), vec![8, 0, 0, 0, 8, 0, 0, 0]);

        let vec: Vec<Vec<u8>> = vec![vec![0, 1, 2], vec![11, 22, 33]];
        assert_eq!(
            vec.as_ssz_bytes(),
            vec![8, 0, 0, 0, 11, 0, 0, 0, 0, 1, 2, 11, 22, 33]
        );
    }

    #[test]
    fn ssz_encode_option_u16() {
        assert_eq!(Some(65535_u16).as_ssz_bytes(), vec![1, 0, 0, 0, 255, 255]);

        let none: Option<u16> = None;
        assert_eq!(none.as_ssz_bytes(), vec![0, 0, 0, 0]);
    }

    #[test]
    fn ssz_encode_option_vec_u16() {
        assert_eq!(
            Some(vec![0_u16, 1]).as_ssz_bytes(),
            vec![1, 0, 0, 0, 0, 0, 1, 0]
        );

        let none: Option<Vec<u16>> = None;
        assert_eq!(none.as_ssz_bytes(), vec![0, 0, 0, 0]);
    }

    #[test]
    fn ssz_encode_u8() {
        assert_eq!(0_u8.as_ssz_bytes(), vec![0]);
        assert_eq!(1_u8.as_ssz_bytes(), vec![1]);
        assert_eq!(100_u8.as_ssz_bytes(), vec![100]);
        assert_eq!(255_u8.as_ssz_bytes(), vec![255]);
    }

    #[test]
    fn ssz_encode_u16() {
        assert_eq!(1_u16.as_ssz_bytes(), vec![1, 0]);
        assert_eq!(100_u16.as_ssz_bytes(), vec![100, 0]);
        assert_eq!((1_u16 << 8).as_ssz_bytes(), vec![0, 1]);
        assert_eq!(65535_u16.as_ssz_bytes(), vec![255, 255]);
    }

    #[test]
    fn ssz_encode_u32() {
        assert_eq!(1_u32.as_ssz_bytes(), vec![1, 0, 0, 0]);
        assert_eq!(100_u32.as_ssz_bytes(), vec![100, 0, 0, 0]);
        assert_eq!((1_u32 << 16).as_ssz_bytes(), vec![0, 0, 1, 0]);
        assert_eq!((1_u32 << 24).as_ssz_bytes(), vec![0, 0, 0, 1]);
        assert_eq!((!0_u32).as_ssz_bytes(), vec![255, 255, 255, 255]);
    }

    #[test]
    fn ssz_encode_u64() {
        assert_eq!(1_u64.as_ssz_bytes(), vec![1, 0, 0, 0, 0, 0, 0, 0]);
        assert_eq!(
            (!0_u64).as_ssz_bytes(),
            vec![255, 255, 255, 255, 255, 255, 255, 255]
        );
    }

    #[test]
    fn ssz_encode_usize() {
        assert_eq!(1_usize.as_ssz_bytes(), vec![1, 0, 0, 0, 0, 0, 0, 0]);
        assert_eq!(
            (!0_usize).as_ssz_bytes(),
            vec![255, 255, 255, 255, 255, 255, 255, 255]
        );
    }

    #[test]
    fn ssz_encode_bool() {
        assert_eq!(true.as_ssz_bytes(), vec![1]);
        assert_eq!(false.as_ssz_bytes(), vec![0]);
    }

    #[test]
    fn ssz_encode_h256() {
        assert_eq!(H256::from(&[0; 32]).as_ssz_bytes(), vec![0; 32]);
        assert_eq!(H256::from(&[1; 32]).as_ssz_bytes(), vec![1; 32]);

        let bytes = vec![
            1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0,
        ];

        assert_eq!(H256::from_slice(&bytes).as_ssz_bytes(), bytes);
    }

    #[test]
    fn ssz_encode_u8_array_4() {
        assert_eq!([0, 0, 0, 0].as_ssz_bytes(), vec![0; 4]);
        assert_eq!([1, 0, 0, 0].as_ssz_bytes(), vec![1, 0, 0, 0]);
        assert_eq!([1, 2, 3, 4].as_ssz_bytes(), vec![1, 2, 3, 4]);
    }
}
<commit_msg>fix encoding impl for usize on 32-bit architectures<commit_after>use super::*;
use core::num::NonZeroUsize;
use ethereum_types::{H256, U128, U256};

macro_rules! impl_encodable_for_uint {
    ($type: ident, $bit_size: expr) => {
        impl Encode for $type {
            fn is_ssz_fixed_len() -> bool {
                true
            }

            fn ssz_fixed_len() -> usize {
                $bit_size / 8
            }

            fn ssz_append(&self, buf: &mut Vec<u8>) {
                buf.extend_from_slice(&self.to_le_bytes());
            }
        }
    };
}

impl_encodable_for_uint!(u8, 8);
impl_encodable_for_uint!(u16, 16);
impl_encodable_for_uint!(u32, 32);
impl_encodable_for_uint!(u64, 64);

#[cfg(target_pointer_width = "32")]
impl_encodable_for_uint!(usize, 32);

#[cfg(target_pointer_width = "64")]
impl_encodable_for_uint!(usize, 64);

/// The SSZ "union" type.
impl<T: Encode> Encode for Option<T> {
    fn is_ssz_fixed_len() -> bool {
        false
    }

    fn ssz_append(&self, buf: &mut Vec<u8>) {
        match self {
            None => buf.append(&mut encode_union_index(0)),
            Some(t) => {
                buf.append(&mut encode_union_index(1));
                t.ssz_append(buf);
            }
        }
    }
}

impl<T: Encode> Encode for Vec<T> {
    fn is_ssz_fixed_len() -> bool {
        false
    }

    fn ssz_append(&self, buf: &mut Vec<u8>) {
        if T::is_ssz_fixed_len() {
            buf.reserve(T::ssz_fixed_len() * self.len());

            for item in self {
                item.ssz_append(buf);
            }
        } else {
            let mut encoder = SszEncoder::list(buf, self.len() * BYTES_PER_LENGTH_OFFSET);

            for item in self {
                encoder.append(item);
            }

            encoder.finalize();
        }
    }
}

impl Encode for bool {
    fn is_ssz_fixed_len() -> bool {
        true
    }

    fn ssz_fixed_len() -> usize {
        1
    }

    fn ssz_append(&self, buf: &mut Vec<u8>) {
        buf.extend_from_slice(&(*self as u8).to_le_bytes());
    }
}

impl Encode for NonZeroUsize {
    fn is_ssz_fixed_len() -> bool {
        <usize as Encode>::is_ssz_fixed_len()
    }

    fn ssz_fixed_len() -> usize {
        <usize as Encode>::ssz_fixed_len()
    }

    fn ssz_append(&self, buf: &mut Vec<u8>) {
        self.get().ssz_append(buf)
    }
}

impl Encode for H256 {
    fn is_ssz_fixed_len() -> bool {
        true
    }

    fn ssz_fixed_len() -> usize {
        32
    }

    fn ssz_append(&self, buf: &mut Vec<u8>) {
        buf.extend_from_slice(self.as_bytes());
    }
}

impl Encode for U256 {
    fn is_ssz_fixed_len() -> bool {
        true
    }

    fn ssz_fixed_len() -> usize {
        32
    }

    fn ssz_append(&self, buf: &mut Vec<u8>) {
        let n = <Self as Encode>::ssz_fixed_len();
        let s = buf.len();

        buf.resize(s + n, 0);
        self.to_little_endian(&mut buf[s..]);
    }
}

impl Encode for U128 {
    fn is_ssz_fixed_len() -> bool {
        true
    }

    fn ssz_fixed_len() -> usize {
        16
    }

    fn ssz_append(&self, buf: &mut Vec<u8>) {
        let n = <Self as Encode>::ssz_fixed_len();
        let s = buf.len();

        buf.resize(s + n, 0);
        self.to_little_endian(&mut buf[s..]);
    }
}

macro_rules! impl_encodable_for_u8_array {
    ($len: expr) => {
        impl Encode for [u8; $len] {
            fn is_ssz_fixed_len() -> bool {
                true
            }

            fn ssz_fixed_len() -> usize {
                $len
            }

            fn ssz_append(&self, buf: &mut Vec<u8>) {
                buf.extend_from_slice(&self[..]);
            }
        }
    };
}

impl_encodable_for_u8_array!(4);
impl_encodable_for_u8_array!(32);

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

    #[test]
    fn vec_of_u8() {
        let vec: Vec<u8> = vec![];
        assert_eq!(vec.as_ssz_bytes(), vec![]);

        let vec: Vec<u8> = vec![1];
        assert_eq!(vec.as_ssz_bytes(), vec![1]);

        let vec: Vec<u8> = vec![0, 1, 2, 3];
        assert_eq!(vec.as_ssz_bytes(), vec![0, 1, 2, 3]);
    }

    #[test]
    fn vec_of_vec_of_u8() {
        let vec: Vec<Vec<u8>> = vec![];
        assert_eq!(vec.as_ssz_bytes(), vec![]);

        let vec: Vec<Vec<u8>> = vec![vec![]];
        assert_eq!(vec.as_ssz_bytes(), vec![4, 0, 0, 0]);

        let vec: Vec<Vec<u8>> = vec![vec![], vec![]];
        assert_eq!(vec.as_ssz_bytes(), vec![8, 0, 0, 0, 8, 0, 0, 0]);

        let vec: Vec<Vec<u8>> = vec![vec![0, 1, 2], vec![11, 22, 33]];
        assert_eq!(
            vec.as_ssz_bytes(),
            vec![8, 0, 0, 0, 11, 0, 0, 0, 0, 1, 2, 11, 22, 33]
        );
    }

    #[test]
    fn ssz_encode_option_u16() {
        assert_eq!(Some(65535_u16).as_ssz_bytes(), vec![1, 0, 0, 0, 255, 255]);

        let none: Option<u16> = None;
        assert_eq!(none.as_ssz_bytes(), vec![0, 0, 0, 0]);
    }

    #[test]
    fn ssz_encode_option_vec_u16() {
        assert_eq!(
            Some(vec![0_u16, 1]).as_ssz_bytes(),
            vec![1, 0, 0, 0, 0, 0, 1, 0]
        );

        let none: Option<Vec<u16>> = None;
        assert_eq!(none.as_ssz_bytes(), vec![0, 0, 0, 0]);
    }

    #[test]
    fn ssz_encode_u8() {
        assert_eq!(0_u8.as_ssz_bytes(), vec![0]);
        assert_eq!(1_u8.as_ssz_bytes(), vec![1]);
        assert_eq!(100_u8.as_ssz_bytes(), vec![100]);
        assert_eq!(255_u8.as_ssz_bytes(), vec![255]);
    }

    #[test]
    fn ssz_encode_u16() {
        assert_eq!(1_u16.as_ssz_bytes(), vec![1, 0]);
        assert_eq!(100_u16.as_ssz_bytes(), vec![100, 0]);
        assert_eq!((1_u16 << 8).as_ssz_bytes(), vec![0, 1]);
        assert_eq!(65535_u16.as_ssz_bytes(), vec![255, 255]);
    }

    #[test]
    fn ssz_encode_u32() {
        assert_eq!(1_u32.as_ssz_bytes(), vec![1, 0, 0, 0]);
        assert_eq!(100_u32.as_ssz_bytes(), vec![100, 0, 0, 0]);
        assert_eq!((1_u32 << 16).as_ssz_bytes(), vec![0, 0, 1, 0]);
        assert_eq!((1_u32 << 24).as_ssz_bytes(), vec![0, 0, 0, 1]);
        assert_eq!((!0_u32).as_ssz_bytes(), vec![255, 255, 255, 255]);
    }

    #[test]
    fn ssz_encode_u64() {
        assert_eq!(1_u64.as_ssz_bytes(), vec![1, 0, 0, 0, 0, 0, 0, 0]);
        assert_eq!(
            (!0_u64).as_ssz_bytes(),
            vec![255, 255, 255, 255, 255, 255, 255, 255]
        );
    }

    #[test]
    fn ssz_encode_usize() {
        assert_eq!(1_usize.as_ssz_bytes(), vec![1, 0, 0, 0, 0, 0, 0, 0]);
        assert_eq!(
            (!0_usize).as_ssz_bytes(),
            vec![255, 255, 255, 255, 255, 255, 255, 255]
        );
    }

    #[test]
    fn ssz_encode_bool() {
        assert_eq!(true.as_ssz_bytes(), vec![1]);
        assert_eq!(false.as_ssz_bytes(), vec![0]);
    }

    #[test]
    fn ssz_encode_h256() {
        assert_eq!(H256::from(&[0; 32]).as_ssz_bytes(), vec![0; 32]);
        assert_eq!(H256::from(&[1; 32]).as_ssz_bytes(), vec![1; 32]);

        let bytes = vec![
            1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0,
        ];

        assert_eq!(H256::from_slice(&bytes).as_ssz_bytes(), bytes);
    }

    #[test]
    fn ssz_encode_u8_array_4() {
        assert_eq!([0, 0, 0, 0].as_ssz_bytes(), vec![0; 4]);
        assert_eq!([1, 0, 0, 0].as_ssz_bytes(), vec![1, 0, 0, 0]);
        assert_eq!([1, 2, 3, 4].as_ssz_bytes(), vec![1, 2, 3, 4]);
    }
}
<|endoftext|>


<commit_before>// Syntax: master_server [ip address (0.0.0.0 by default)]
// This was created for HaloMD.

// If the server does not respond in at least this many seconds, it will be dropped from the list.
const DROP_TIME : i64 = 60;

// Blacklist for blocking IPs. Separate with newlines. Any line that starts with a # is ignored.
// Blacklisting IPs ignores heartbeat and keepalive packets from an IP address.
// That means that servers that are banned will not be immediately removed, but will time out, instead.
const BLACKLIST_FILE : &'static str = "blacklist.txt";

// Read the blacklist every x amount of seconds.
const BLACKLIST_UPDATE_TIME : u32 = 60;

// Note: The master server must have TCP 29920 open and UDP 27900 open.
const BROADCAST_PORT_UDP : u16 = 27900;
const SERVER_LIST_PORT_TCP : u16 = 29920;

// Opcode info from game packets
const OPCODE_INDEX : usize = 0;
const OPCODE_AND_HANDSHAKE_LENGTH : usize = 5;

// Broadcast packet type opcodes.
const KEEPALIVE : u8 = 8;
const HEARTBEAT : u8 = 3;

use std::net::{UdpSocket,TcpListener,SocketAddr};
use std::net::SocketAddr::{V4,V6};
use std::io::{Write,BufReader,BufRead};
use std::env;
use std::fs::File;
use std::thread;
use std::thread::Builder;
use std::sync::{Arc, Mutex};

extern crate time;
use time::{SteadyTime,Duration};

mod error_macros;

mod halo_server;
use halo_server::HaloServer;

mod heartbeat_packet;
use heartbeat_packet::{HeartbeatPacket,GAMEEXITED,VALID_GAME_VERSIONS,HALO_RETAIL};

trait IPString {
    fn ip_string(&self) -> String;
}

impl IPString for SocketAddr {
    fn ip_string(&self) -> String {
        match *self {
            V4(ipv4) => ipv4.ip().to_string(),
            V6(ipv6) => "[".to_string() + &ipv6.ip().to_string() + "]"
        }
    }
}

fn main() {
    let count = env::args().count();
    let ip = if count == 2 {
        let j : Vec<_> = env::args().collect();
        j[1].to_string()
    }
    else if count == 1 {
        "0.0.0.0".to_string()
    }
    else {
        println!("Only one argument is allowed: the IP to bind to.");
        return;
    };

    // We need to bind on two different ports. If it failed to bind (invalid IP, port is taken), then we must make sure this is known.
    let halo_socket = unwrap_result_or_bail!(UdpSocket::bind((&ip as &str,BROADCAST_PORT_UDP)), {
        println!("Failed creating a UDP socket at {}:{}.",ip,BROADCAST_PORT_UDP);
        return;
    });

    let client_socket = unwrap_result_or_bail!(TcpListener::bind((&ip as &str,SERVER_LIST_PORT_TCP)), {
        println!("Error listening to TCP at {}:{}.",ip,SERVER_LIST_PORT_TCP);
        return;
    });

    // Mutex for thread safety.
    let servers_halo: Vec<HaloServer> = Vec::new();
    let servers_mut_udp = Arc::new(Mutex::new(servers_halo));
    let servers_mut_tcp = servers_mut_udp.clone();
    let servers_mut_destruction = servers_mut_udp.clone();

    // Destruction thread. This will remove servers that have not broadcasted their presence in a while.
    let _ = Builder::new().name("destruction_thread".to_string()).spawn(move || {
        loop {
            thread::sleep_ms(10 * 1000);
            let mut servers = servers_mut_destruction.lock().unwrap();
            let timenow = SteadyTime::now();
            servers.retain(|x| x.last_alive + Duration::seconds(DROP_TIME) > timenow);
        }
    });

    // Blacklist mutex. Concurrency needs to be safe, my friend.
    let blacklist: Option<Vec<String>> = None;
    let blacklist_update = Arc::new(Mutex::new(blacklist));
    let blacklist_udp = blacklist_update.clone();

    // Blacklist read thread.
    let _ = Builder::new().name("blacklist_thread".to_string()).spawn(move || {
        let valid_line = |x: &str| -> bool { x.trim().len() > 0 && !x.starts_with("#") };
        loop {
            // Placed in a block so blacklist is unlocked before sleeping to prevent threads from being locked for too long.
            {
                let mut blacklist_ref = blacklist_update.lock().unwrap();
                *blacklist_ref =
                    File::open(BLACKLIST_FILE).
                    map(|file|
                        BufReader::new(&file).lines().
                        filter_map(|line| line.ok().and_then(|x| if valid_line(&x) { Some(x) } else { None })).
                        collect()
                    ).ok();
            }
            thread::sleep_ms(BLACKLIST_UPDATE_TIME * 1000);
        }
    });

    // TCP server thread. This is for the HaloMD application.
    let _ = Builder::new().name("halomd_thread".to_string()).spawn(move || {
        loop {
            for stream in client_socket.incoming() {
                let mut client = unwrap_option_or_bail!(stream.ok(), { continue });
                let ip = unwrap_option_or_bail!(client.peer_addr().ok(), { continue }).ip_string();
                let mut ips = String::new();

                // Make servers_ref go out of scope to unlock it for other threads, since we don't need it.
                {
                    let servers_ref = servers_mut_tcp.lock().unwrap();
                    let servers = (*servers_ref).iter();

                    for j in servers {
                        ips.push_str(&(j.to_string()));
                        ips.push('\n');
                    }
                }

                // Some number placed after the requester's IP. If you ask me, the source code was abducted by aliens, and this is a tracking number. Regardless, it's needed.
                ips.push_str(&ip);
                ips.push_str(":49149:3425");

                // We may be here a while. Just in case...
                // May want to consider some lightweight thread library in the future, or some non-blocking polling mechanism
                thread::spawn( move || {
                    let _ = client.write_all(ips.as_bytes());
                });
            }
        }
    });

    // UDP server is run on the main thread. Servers broadcast their presence here.

    let mut buffer = [0; 2048];
    loop {
        let (length, source) = unwrap_option_or_bail!(halo_socket.recv_from(&mut buffer).ok(), { continue });

        if length <= OPCODE_INDEX {
            continue;
        }

        if buffer[OPCODE_INDEX] != KEEPALIVE && buffer[OPCODE_INDEX] != HEARTBEAT {
            continue;
        }

        let client_ip = source.ip_string();

        let blacklist_ref = blacklist_udp.lock().unwrap();
        if (*blacklist_ref).as_ref().map(|blacklist| blacklist.contains(&client_ip)).unwrap_or(false) {
            continue;
        }

        // Heartbeat packet. These contain null-terminated C strings and are ordered in key1[0]value1[0]key2[0]value2[0]key3[0]value3[0] where [0] is a byte equal to 0x00.
        if buffer[OPCODE_INDEX] == HEARTBEAT && length > OPCODE_AND_HANDSHAKE_LENGTH {

            let mut servers = servers_mut_udp.lock().unwrap();

            match HeartbeatPacket::from_buffer(&buffer[OPCODE_AND_HANDSHAKE_LENGTH..length]) {
                None => {},
                Some(packet) => {
                    let updatetime = SteadyTime::now();
                    match servers.iter_mut().position(|x| *x == (&client_ip, packet.localport)) {
                        None => {
                            if packet.gamename == HALO_RETAIL && VALID_GAME_VERSIONS.contains(&&*packet.gamever) {
                                (*servers).push(HaloServer { ip:client_ip, port: packet.localport, last_alive: updatetime });
                            }
                        }
                        Some(k) => {
                            servers[k].last_alive = updatetime;
                            if packet.statechanged == GAMEEXITED {
                                servers.remove(k);
                            }
                        }
                    };
                }
            };
        }

        // Keepalive packet. We need to rely on the origin's port for this, unfortunately. This may mean that the source port is incorrect if the port was changed with NAT.
        else if buffer[OPCODE_INDEX] == KEEPALIVE {
            let mut servers_ref = servers_mut_udp.lock().unwrap();
            let servers = (*servers_ref).iter_mut();

            for i in servers {
                if *i == (&client_ip, source.port()) {
                    i.last_alive = SteadyTime::now();
                    break;
                }
            }
        }
    }
}
<commit_msg>s/Error/Failed/<commit_after>// Syntax: master_server [ip address (0.0.0.0 by default)]
// This was created for HaloMD.

// If the server does not respond in at least this many seconds, it will be dropped from the list.
const DROP_TIME : i64 = 60;

// Blacklist for blocking IPs. Separate with newlines. Any line that starts with a # is ignored.
// Blacklisting IPs ignores heartbeat and keepalive packets from an IP address.
// That means that servers that are banned will not be immediately removed, but will time out, instead.
const BLACKLIST_FILE : &'static str = "blacklist.txt";

// Read the blacklist every x amount of seconds.
const BLACKLIST_UPDATE_TIME : u32 = 60;

// Note: The master server must have TCP 29920 open and UDP 27900 open.
const BROADCAST_PORT_UDP : u16 = 27900;
const SERVER_LIST_PORT_TCP : u16 = 29920;

// Opcode info from game packets
const OPCODE_INDEX : usize = 0;
const OPCODE_AND_HANDSHAKE_LENGTH : usize = 5;

// Broadcast packet type opcodes.
const KEEPALIVE : u8 = 8;
const HEARTBEAT : u8 = 3;

use std::net::{UdpSocket,TcpListener,SocketAddr};
use std::net::SocketAddr::{V4,V6};
use std::io::{Write,BufReader,BufRead};
use std::env;
use std::fs::File;
use std::thread;
use std::thread::Builder;
use std::sync::{Arc, Mutex};

extern crate time;
use time::{SteadyTime,Duration};

mod error_macros;

mod halo_server;
use halo_server::HaloServer;

mod heartbeat_packet;
use heartbeat_packet::{HeartbeatPacket,GAMEEXITED,VALID_GAME_VERSIONS,HALO_RETAIL};

trait IPString {
    fn ip_string(&self) -> String;
}

impl IPString for SocketAddr {
    fn ip_string(&self) -> String {
        match *self {
            V4(ipv4) => ipv4.ip().to_string(),
            V6(ipv6) => "[".to_string() + &ipv6.ip().to_string() + "]"
        }
    }
}

fn main() {
    let count = env::args().count();
    let ip = if count == 2 {
        let j : Vec<_> = env::args().collect();
        j[1].to_string()
    }
    else if count == 1 {
        "0.0.0.0".to_string()
    }
    else {
        println!("Only one argument is allowed: the IP to bind to.");
        return;
    };

    // We need to bind on two different ports. If it failed to bind (invalid IP, port is taken), then we must make sure this is known.
    let halo_socket = unwrap_result_or_bail!(UdpSocket::bind((&ip as &str,BROADCAST_PORT_UDP)), {
        println!("Failed creating a UDP socket at {}:{}.",ip,BROADCAST_PORT_UDP);
        return;
    });

    let client_socket = unwrap_result_or_bail!(TcpListener::bind((&ip as &str,SERVER_LIST_PORT_TCP)), {
        println!("Failed listening to TCP at {}:{}.",ip,SERVER_LIST_PORT_TCP);
        return;
    });

    // Mutex for thread safety.
    let servers_halo: Vec<HaloServer> = Vec::new();
    let servers_mut_udp = Arc::new(Mutex::new(servers_halo));
    let servers_mut_tcp = servers_mut_udp.clone();
    let servers_mut_destruction = servers_mut_udp.clone();

    // Destruction thread. This will remove servers that have not broadcasted their presence in a while.
    let _ = Builder::new().name("destruction_thread".to_string()).spawn(move || {
        loop {
            thread::sleep_ms(10 * 1000);
            let mut servers = servers_mut_destruction.lock().unwrap();
            let timenow = SteadyTime::now();
            servers.retain(|x| x.last_alive + Duration::seconds(DROP_TIME) > timenow);
        }
    });

    // Blacklist mutex. Concurrency needs to be safe, my friend.
    let blacklist: Option<Vec<String>> = None;
    let blacklist_update = Arc::new(Mutex::new(blacklist));
    let blacklist_udp = blacklist_update.clone();

    // Blacklist read thread.
    let _ = Builder::new().name("blacklist_thread".to_string()).spawn(move || {
        let valid_line = |x: &str| -> bool { x.trim().len() > 0 && !x.starts_with("#") };
        loop {
            // Placed in a block so blacklist is unlocked before sleeping to prevent threads from being locked for too long.
            {
                let mut blacklist_ref = blacklist_update.lock().unwrap();
                *blacklist_ref =
                    File::open(BLACKLIST_FILE).
                    map(|file|
                        BufReader::new(&file).lines().
                        filter_map(|line| line.ok().and_then(|x| if valid_line(&x) { Some(x) } else { None })).
                        collect()
                    ).ok();
            }
            thread::sleep_ms(BLACKLIST_UPDATE_TIME * 1000);
        }
    });

    // TCP server thread. This is for the HaloMD application.
    let _ = Builder::new().name("halomd_thread".to_string()).spawn(move || {
        loop {
            for stream in client_socket.incoming() {
                let mut client = unwrap_option_or_bail!(stream.ok(), { continue });
                let ip = unwrap_option_or_bail!(client.peer_addr().ok(), { continue }).ip_string();
                let mut ips = String::new();

                // Make servers_ref go out of scope to unlock it for other threads, since we don't need it.
                {
                    let servers_ref = servers_mut_tcp.lock().unwrap();
                    let servers = (*servers_ref).iter();

                    for j in servers {
                        ips.push_str(&(j.to_string()));
                        ips.push('\n');
                    }
                }

                // Some number placed after the requester's IP. If you ask me, the source code was abducted by aliens, and this is a tracking number. Regardless, it's needed.
                ips.push_str(&ip);
                ips.push_str(":49149:3425");

                // We may be here a while. Just in case...
                // May want to consider some lightweight thread library in the future, or some non-blocking polling mechanism
                thread::spawn( move || {
                    let _ = client.write_all(ips.as_bytes());
                });
            }
        }
    });

    // UDP server is run on the main thread. Servers broadcast their presence here.

    let mut buffer = [0; 2048];
    loop {
        let (length, source) = unwrap_option_or_bail!(halo_socket.recv_from(&mut buffer).ok(), { continue });

        if length <= OPCODE_INDEX {
            continue;
        }

        if buffer[OPCODE_INDEX] != KEEPALIVE && buffer[OPCODE_INDEX] != HEARTBEAT {
            continue;
        }

        let client_ip = source.ip_string();

        let blacklist_ref = blacklist_udp.lock().unwrap();
        if (*blacklist_ref).as_ref().map(|blacklist| blacklist.contains(&client_ip)).unwrap_or(false) {
            continue;
        }

        // Heartbeat packet. These contain null-terminated C strings and are ordered in key1[0]value1[0]key2[0]value2[0]key3[0]value3[0] where [0] is a byte equal to 0x00.
        if buffer[OPCODE_INDEX] == HEARTBEAT && length > OPCODE_AND_HANDSHAKE_LENGTH {

            let mut servers = servers_mut_udp.lock().unwrap();

            match HeartbeatPacket::from_buffer(&buffer[OPCODE_AND_HANDSHAKE_LENGTH..length]) {
                None => {},
                Some(packet) => {
                    let updatetime = SteadyTime::now();
                    match servers.iter_mut().position(|x| *x == (&client_ip, packet.localport)) {
                        None => {
                            if packet.gamename == HALO_RETAIL && VALID_GAME_VERSIONS.contains(&&*packet.gamever) {
                                (*servers).push(HaloServer { ip:client_ip, port: packet.localport, last_alive: updatetime });
                            }
                        }
                        Some(k) => {
                            servers[k].last_alive = updatetime;
                            if packet.statechanged == GAMEEXITED {
                                servers.remove(k);
                            }
                        }
                    };
                }
            };
        }

        // Keepalive packet. We need to rely on the origin's port for this, unfortunately. This may mean that the source port is incorrect if the port was changed with NAT.
        else if buffer[OPCODE_INDEX] == KEEPALIVE {
            let mut servers_ref = servers_mut_udp.lock().unwrap();
            let servers = (*servers_ref).iter_mut();

            for i in servers {
                if *i == (&client_ip, source.port()) {
                    i.last_alive = SteadyTime::now();
                    break;
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

#![deny(clippy::all)]

mod client;
mod code_action;
mod completion;
mod diagnostic_reporter;
mod explore_schema_for_type;
mod goto_definition;
mod graphql_tools;
mod hover;
pub mod js_language_server;
mod location;
mod lsp_extra_data_provider;
pub mod lsp_process_error;
pub mod lsp_runtime_error;
pub mod node_resolution_info;
mod references;
pub mod resolution_path;
mod resolved_types_at_location;
mod search_schema_items;
mod server;
mod shutdown;
mod status_reporter;
mod status_updater;
mod text_documents;
mod utils;
use common::PerfLogger;
pub use js_language_server::JSLanguageServer;
use log::debug;
pub use lsp_extra_data_provider::{FieldDefinitionSourceInfo, LSPExtraDataProvider};
use lsp_process_error::LSPProcessResult;
pub use lsp_runtime_error::{LSPRuntimeError, LSPRuntimeResult};
use lsp_server::Connection;
use relay_compiler::config::Config;
use schema_documentation::{SchemaDocumentation, SchemaDocumentationLoader};
pub use server::LSPNotificationDispatch;
pub use server::LSPRequestDispatch;
pub use server::{GlobalState, LSPState, Schemas};
use std::sync::Arc;
pub use utils::position_to_offset;
#[cfg(test)]
#[macro_use]
extern crate assert_matches;

pub async fn start_language_server<
    TPerfLogger,
    TSchemaDocumentation: SchemaDocumentation + 'static,
>(
    config: Config,
    perf_logger: Arc<TPerfLogger>,
    extra_data_provider: Box<dyn LSPExtraDataProvider + Send + Sync>,
    schema_documentation_loader: Option<Box<dyn SchemaDocumentationLoader<TSchemaDocumentation>>>,
    js_language_server: Option<
        Box<dyn JSLanguageServer<TState = LSPState<TPerfLogger, TSchemaDocumentation>>>,
    >,
) -> LSPProcessResult<()>
where
    TPerfLogger: PerfLogger + 'static,
{
    let (connection, io_handles) = Connection::stdio();
    debug!("Initialized stdio transport layer");
    let params = server::initialize(&connection)?;
    debug!("JSON-RPC handshake completed");
    server::run(
        connection,
        config,
        params,
        perf_logger,
        extra_data_provider,
        schema_documentation_loader,
        js_language_server,
    )
    .await?;
    io_handles.join()?;
    Ok(())
}

#[cfg(test)]
mod tests {
    use super::client;
    use super::lsp_process_error::LSPProcessResult;
    use super::server;
    use lsp_server::Connection;
    use lsp_types::{ClientCapabilities, InitializeParams};
    #[test]
    fn initialize() -> LSPProcessResult<()> {
        // Test with an in-memory connection pair
        let (connection, client) = Connection::memory();
        // Mock set of client parameters. The `root_path` field is deprecated, but
        // still required to construct the params, so we allow deprecated fields here.
        #[allow(deprecated)]
        let init_params = InitializeParams {
            process_id: Some(1),
            root_path: None,
            root_uri: None,
            initialization_options: None,
            capabilities: ClientCapabilities::default(),
            trace: None,
            workspace_folders: None,
            client_info: None,
            locale: None,
        };
        client::initialize(&client, &init_params, 0);
        let params = server::initialize(&connection)?;
        assert_eq!(params, init_params);
        Ok(())
    }
}
<commit_msg>resolve_executable_definitions<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

#![deny(clippy::all)]

mod client;
mod code_action;
mod completion;
mod diagnostic_reporter;
mod explore_schema_for_type;
mod goto_definition;
mod graphql_tools;
mod hover;
pub mod js_language_server;
mod location;
mod lsp_extra_data_provider;
pub mod lsp_process_error;
pub mod lsp_runtime_error;
pub mod node_resolution_info;
mod references;
pub mod resolution_path;
mod resolved_types_at_location;
mod search_schema_items;
mod server;
mod shutdown;
mod status_reporter;
mod status_updater;
mod text_documents;
pub mod utils;
use common::PerfLogger;
pub use js_language_server::JSLanguageServer;
use log::debug;
pub use lsp_extra_data_provider::{FieldDefinitionSourceInfo, LSPExtraDataProvider};
use lsp_process_error::LSPProcessResult;
pub use lsp_runtime_error::{LSPRuntimeError, LSPRuntimeResult};
use lsp_server::Connection;
use relay_compiler::config::Config;
use schema_documentation::{SchemaDocumentation, SchemaDocumentationLoader};
pub use server::LSPNotificationDispatch;
pub use server::LSPRequestDispatch;
pub use server::{GlobalState, LSPState, Schemas};
use std::sync::Arc;
pub use utils::position_to_offset;
#[cfg(test)]
#[macro_use]
extern crate assert_matches;

pub async fn start_language_server<
    TPerfLogger,
    TSchemaDocumentation: SchemaDocumentation + 'static,
>(
    config: Config,
    perf_logger: Arc<TPerfLogger>,
    extra_data_provider: Box<dyn LSPExtraDataProvider + Send + Sync>,
    schema_documentation_loader: Option<Box<dyn SchemaDocumentationLoader<TSchemaDocumentation>>>,
    js_language_server: Option<
        Box<dyn JSLanguageServer<TState = LSPState<TPerfLogger, TSchemaDocumentation>>>,
    >,
) -> LSPProcessResult<()>
where
    TPerfLogger: PerfLogger + 'static,
{
    let (connection, io_handles) = Connection::stdio();
    debug!("Initialized stdio transport layer");
    let params = server::initialize(&connection)?;
    debug!("JSON-RPC handshake completed");
    server::run(
        connection,
        config,
        params,
        perf_logger,
        extra_data_provider,
        schema_documentation_loader,
        js_language_server,
    )
    .await?;
    io_handles.join()?;
    Ok(())
}

#[cfg(test)]
mod tests {
    use super::client;
    use super::lsp_process_error::LSPProcessResult;
    use super::server;
    use lsp_server::Connection;
    use lsp_types::{ClientCapabilities, InitializeParams};
    #[test]
    fn initialize() -> LSPProcessResult<()> {
        // Test with an in-memory connection pair
        let (connection, client) = Connection::memory();
        // Mock set of client parameters. The `root_path` field is deprecated, but
        // still required to construct the params, so we allow deprecated fields here.
        #[allow(deprecated)]
        let init_params = InitializeParams {
            process_id: Some(1),
            root_path: None,
            root_uri: None,
            initialization_options: None,
            capabilities: ClientCapabilities::default(),
            trace: None,
            workspace_folders: None,
            client_info: None,
            locale: None,
        };
        client::initialize(&client, &init_params, 0);
        let params = server::initialize(&connection)?;
        assert_eq!(params, init_params);
        Ok(())
    }
}
<|endoftext|>