<commit_before>use syntax::{
    ast::{self, AstNode},
    SyntaxElement, TextRange, TextSize, T,
};

use crate::{AssistContext, AssistId, AssistKind, Assists};

// Assist: remove_dbg
//
// Removes `dbg!()` macro call.
//
// ```
// fn main() {
//     <|>dbg!(92);
// }
// ```
// ->
// ```
// fn main() {
//     92;
// }
// ```
pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let macro_call = ctx.find_node_at_offset::<ast::MacroCall>()?;
    let new_contents = adjusted_macro_contents(&macro_call)?;

    let macro_text_range = macro_call.syntax().text_range();
    let macro_end = if macro_call.semicolon_token().is_some() {
        macro_text_range.end() - TextSize::of(';')
    } else {
        macro_text_range.end()
    };

    acc.add(
        AssistId("remove_dbg", AssistKind::Refactor),
        "Remove dbg!()",
        macro_text_range,
        |builder| {
            builder.replace(TextRange::new(macro_text_range.start(), macro_end), new_contents);
        },
    )
}

fn adjusted_macro_contents(macro_call: &ast::MacroCall) -> Option<String> {
    let contents = get_valid_macrocall_contents(&macro_call, "dbg")?;
    let macro_text_with_brackets = macro_call.token_tree()?.syntax().text();
    let macro_text_in_brackets = macro_text_with_brackets.slice(TextRange::new(
        TextSize::of('('),
        macro_text_with_brackets.len() - TextSize::of(')'),
    ));

    let is_leaf = macro_call.syntax().next_sibling().is_none();
    Some(if !is_leaf && needs_parentheses_around_macro_contents(contents) {
        format!("({})", macro_text_in_brackets)
    } else {
        macro_text_in_brackets.to_string()
    })
}

/// Verifies that the given macro_call actually matches the given name
/// and contains proper ending tokens, then returns the contents between the ending tokens
fn get_valid_macrocall_contents(
    macro_call: &ast::MacroCall,
    macro_name: &str,
) -> Option<Vec<SyntaxElement>> {
    let path = macro_call.path()?;
    let name_ref = path.segment()?.name_ref()?;

    // Make sure it is actually a dbg-macro call, dbg followed by !
    let excl = path.syntax().next_sibling_or_token()?;
    if name_ref.text() != macro_name || excl.kind() != T![!] {
        return None;
    }

    let mut children_with_tokens = macro_call.token_tree()?.syntax().children_with_tokens();
    let first_child = children_with_tokens.next()?;
    let mut contents_between_brackets = children_with_tokens.collect::<Vec<_>>();
    let last_child = contents_between_brackets.pop()?;

    if contents_between_brackets.is_empty() {
        None
    } else {
        match (first_child.kind(), last_child.kind()) {
            (T!['('], T![')']) | (T!['['], T![']']) | (T!['{'], T!['}']) => {
                Some(contents_between_brackets)
            }
            _ => None,
        }
    }
}

fn needs_parentheses_around_macro_contents(macro_contents: Vec<SyntaxElement>) -> bool {
    if macro_contents.len() < 2 {
        return false;
    }
    let mut unpaired_brackets_in_contents = Vec::new();
    for element in macro_contents {
        match element.kind() {
            T!['('] | T!['['] | T!['{'] => unpaired_brackets_in_contents.push(element),
            T![')'] => {
                if !matches!(unpaired_brackets_in_contents.pop(), Some(correct_bracket) if correct_bracket.kind() == T!['('])
                {
                    return true;
                }
            }
            T![']'] => {
                if !matches!(unpaired_brackets_in_contents.pop(), Some(correct_bracket) if correct_bracket.kind() == T!['['])
                {
                    return true;
                }
            }
            T!['}'] => {
                if !matches!(unpaired_brackets_in_contents.pop(), Some(correct_bracket) if correct_bracket.kind() == T!['{'])
                {
                    return true;
                }
            }
            symbol_kind => {
                let symbol_not_in_bracket = unpaired_brackets_in_contents.is_empty();
                if symbol_not_in_bracket && symbol_kind.is_punct() {
                    return true;
                }
            }
        }
    }
    !unpaired_brackets_in_contents.is_empty()
}

#[cfg(test)]
mod tests {
    use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};

    use super::*;

    #[test]
    fn test_remove_dbg() {
        check_assist(remove_dbg, "<|>dbg!(1 + 1)", "1 + 1");

        check_assist(remove_dbg, "dbg!<|>((1 + 1))", "(1 + 1)");

        check_assist(remove_dbg, "dbg!(1 <|>+ 1)", "1 + 1");

        check_assist(remove_dbg, "let _ = <|>dbg!(1 + 1)", "let _ = 1 + 1");

        check_assist(
            remove_dbg,
            "
fn foo(n: usize) {
    if let Some(_) = dbg!(n.<|>checked_sub(4)) {
        // ...
    }
}
",
            "
fn foo(n: usize) {
    if let Some(_) = n.checked_sub(4) {
        // ...
    }
}
",
        );
    }

    #[test]
    fn test_remove_dbg_with_brackets_and_braces() {
        check_assist(remove_dbg, "dbg![<|>1 + 1]", "1 + 1");
        check_assist(remove_dbg, "dbg!{<|>1 + 1}", "1 + 1");
    }

    #[test]
    fn test_remove_dbg_not_applicable() {
        check_assist_not_applicable(remove_dbg, "<|>vec![1, 2, 3]");
        check_assist_not_applicable(remove_dbg, "<|>dbg(5, 6, 7)");
        check_assist_not_applicable(remove_dbg, "<|>dbg!(5, 6, 7");
    }

    #[test]
    fn test_remove_dbg_target() {
        check_assist_target(
            remove_dbg,
            "
fn foo(n: usize) {
    if let Some(_) = dbg!(n.<|>checked_sub(4)) {
        // ...
    }
}
",
            "dbg!(n.checked_sub(4))",
        );
    }

    #[test]
    fn test_remove_dbg_keep_semicolon() {
        // https://github.com/rust-analyzer/rust-analyzer/issues/5129#issuecomment-651399779
        // not quite though
        // adding a comment at the end of the line makes
        // the ast::MacroCall to include the semicolon at the end
        check_assist(
            remove_dbg,
            r#"let res = <|>dbg!(1 * 20); // needless comment"#,
            r#"let res = 1 * 20; // needless comment"#,
        );
    }

    #[test]
    fn remove_dbg_from_non_leaf_simple_expression() {
        check_assist(
            remove_dbg,
            "
fn main() {
    let mut a = 1;
    while dbg!<|>(a) < 10000 {
        a += 1;
    }
}
",
            "
fn main() {
    let mut a = 1;
    while a < 10000 {
        a += 1;
    }
}
",
        );
    }

    #[test]
    fn test_remove_dbg_keep_expression() {
        check_assist(
            remove_dbg,
            r#"let res = <|>dbg!(a + b).foo();"#,
            r#"let res = (a + b).foo();"#,
        );

        check_assist(remove_dbg, r#"let res = <|>dbg!(2 + 2) * 5"#, r#"let res = (2 + 2) * 5"#);
        check_assist(remove_dbg, r#"let res = <|>dbg![2 + 2] * 5"#, r#"let res = (2 + 2) * 5"#);
    }

    #[test]
    fn test_remove_dbg_from_inside_fn() {
        check_assist_target(
            remove_dbg,
            r#"
fn square(x: u32) -> u32 {
    x * x
}

fn main() {
    let x = square(dbg<|>!(5 + 10));
    println!("{}", x);
}"#,
            "dbg!(5 + 10)",
        );

        check_assist(
            remove_dbg,
            r#"
fn square(x: u32) -> u32 {
    x * x
}

fn main() {
    let x = square(dbg<|>!(5 + 10));
    println!("{}", x);
}"#,
            r#"
fn square(x: u32) -> u32 {
    x * x
}

fn main() {
    let x = square(5 + 10);
    println!("{}", x);
}"#,
        );
    }
}
<commit_msg>Do not leave braces for colons in dbg!<commit_after>use syntax::{
    ast::{self, AstNode},
    SyntaxElement, SyntaxKind, TextRange, TextSize, T,
};

use crate::{AssistContext, AssistId, AssistKind, Assists};

// Assist: remove_dbg
//
// Removes `dbg!()` macro call.
//
// ```
// fn main() {
//     <|>dbg!(92);
// }
// ```
// ->
// ```
// fn main() {
//     92;
// }
// ```
pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let macro_call = ctx.find_node_at_offset::<ast::MacroCall>()?;
    let new_contents = adjusted_macro_contents(&macro_call)?;

    let macro_text_range = macro_call.syntax().text_range();
    let macro_end = if macro_call.semicolon_token().is_some() {
        macro_text_range.end() - TextSize::of(';')
    } else {
        macro_text_range.end()
    };

    acc.add(
        AssistId("remove_dbg", AssistKind::Refactor),
        "Remove dbg!()",
        macro_text_range,
        |builder| {
            builder.replace(TextRange::new(macro_text_range.start(), macro_end), new_contents);
        },
    )
}

fn adjusted_macro_contents(macro_call: &ast::MacroCall) -> Option<String> {
    let contents = get_valid_macrocall_contents(&macro_call, "dbg")?;
    let macro_text_with_brackets = macro_call.token_tree()?.syntax().text();
    let macro_text_in_brackets = macro_text_with_brackets.slice(TextRange::new(
        TextSize::of('('),
        macro_text_with_brackets.len() - TextSize::of(')'),
    ));

    let is_leaf = macro_call.syntax().next_sibling().is_none();
    Some(if !is_leaf && needs_parentheses_around_macro_contents(contents) {
        format!("({})", macro_text_in_brackets)
    } else {
        macro_text_in_brackets.to_string()
    })
}

/// Verifies that the given macro_call actually matches the given name
/// and contains proper ending tokens, then returns the contents between the ending tokens
fn get_valid_macrocall_contents(
    macro_call: &ast::MacroCall,
    macro_name: &str,
) -> Option<Vec<SyntaxElement>> {
    let path = macro_call.path()?;
    let name_ref = path.segment()?.name_ref()?;

    // Make sure it is actually a dbg-macro call, dbg followed by !
    let excl = path.syntax().next_sibling_or_token()?;
    if name_ref.text() != macro_name || excl.kind() != T![!] {
        return None;
    }

    let mut children_with_tokens = macro_call.token_tree()?.syntax().children_with_tokens();
    let first_child = children_with_tokens.next()?;
    let mut contents_between_brackets = children_with_tokens.collect::<Vec<_>>();
    let last_child = contents_between_brackets.pop()?;

    if contents_between_brackets.is_empty() {
        None
    } else {
        match (first_child.kind(), last_child.kind()) {
            (T!['('], T![')']) | (T!['['], T![']']) | (T!['{'], T!['}']) => {
                Some(contents_between_brackets)
            }
            _ => None,
        }
    }
}

fn needs_parentheses_around_macro_contents(macro_contents: Vec<SyntaxElement>) -> bool {
    if macro_contents.len() < 2 {
        return false;
    }
    let mut unpaired_brackets_in_contents = Vec::new();
    for element in macro_contents {
        match element.kind() {
            T!['('] | T!['['] | T!['{'] => unpaired_brackets_in_contents.push(element),
            T![')'] => {
                if !matches!(unpaired_brackets_in_contents.pop(), Some(correct_bracket) if correct_bracket.kind() == T!['('])
                {
                    return true;
                }
            }
            T![']'] => {
                if !matches!(unpaired_brackets_in_contents.pop(), Some(correct_bracket) if correct_bracket.kind() == T!['['])
                {
                    return true;
                }
            }
            T!['}'] => {
                if !matches!(unpaired_brackets_in_contents.pop(), Some(correct_bracket) if correct_bracket.kind() == T!['{'])
                {
                    return true;
                }
            }
            symbol_kind => {
                let symbol_not_in_bracket = unpaired_brackets_in_contents.is_empty();
                if symbol_not_in_bracket
                    && symbol_kind != SyntaxKind::COLON
                    && symbol_kind.is_punct()
                {
                    return true;
                }
            }
        }
    }
    !unpaired_brackets_in_contents.is_empty()
}

#[cfg(test)]
mod tests {
    use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};

    use super::*;

    #[test]
    fn test_remove_dbg() {
        check_assist(remove_dbg, "<|>dbg!(1 + 1)", "1 + 1");

        check_assist(remove_dbg, "dbg!<|>((1 + 1))", "(1 + 1)");

        check_assist(remove_dbg, "dbg!(1 <|>+ 1)", "1 + 1");

        check_assist(remove_dbg, "let _ = <|>dbg!(1 + 1)", "let _ = 1 + 1");

        check_assist(
            remove_dbg,
            "
fn foo(n: usize) {
    if let Some(_) = dbg!(n.<|>checked_sub(4)) {
        // ...
    }
}
",
            "
fn foo(n: usize) {
    if let Some(_) = n.checked_sub(4) {
        // ...
    }
}
",
        );

        check_assist(remove_dbg, "<|>dbg!(Foo::foo_test()).bar()", "Foo::foo_test().bar()");
    }

    #[test]
    fn test_remove_dbg_with_brackets_and_braces() {
        check_assist(remove_dbg, "dbg![<|>1 + 1]", "1 + 1");
        check_assist(remove_dbg, "dbg!{<|>1 + 1}", "1 + 1");
    }

    #[test]
    fn test_remove_dbg_not_applicable() {
        check_assist_not_applicable(remove_dbg, "<|>vec![1, 2, 3]");
        check_assist_not_applicable(remove_dbg, "<|>dbg(5, 6, 7)");
        check_assist_not_applicable(remove_dbg, "<|>dbg!(5, 6, 7");
    }

    #[test]
    fn test_remove_dbg_target() {
        check_assist_target(
            remove_dbg,
            "
fn foo(n: usize) {
    if let Some(_) = dbg!(n.<|>checked_sub(4)) {
        // ...
    }
}
",
            "dbg!(n.checked_sub(4))",
        );
    }

    #[test]
    fn test_remove_dbg_keep_semicolon() {
        // https://github.com/rust-analyzer/rust-analyzer/issues/5129#issuecomment-651399779
        // not quite though
        // adding a comment at the end of the line makes
        // the ast::MacroCall to include the semicolon at the end
        check_assist(
            remove_dbg,
            r#"let res = <|>dbg!(1 * 20); // needless comment"#,
            r#"let res = 1 * 20; // needless comment"#,
        );
    }

    #[test]
    fn remove_dbg_from_non_leaf_simple_expression() {
        check_assist(
            remove_dbg,
            "
fn main() {
    let mut a = 1;
    while dbg!<|>(a) < 10000 {
        a += 1;
    }
}
",
            "
fn main() {
    let mut a = 1;
    while a < 10000 {
        a += 1;
    }
}
",
        );
    }

    #[test]
    fn test_remove_dbg_keep_expression() {
        check_assist(
            remove_dbg,
            r#"let res = <|>dbg!(a + b).foo();"#,
            r#"let res = (a + b).foo();"#,
        );

        check_assist(remove_dbg, r#"let res = <|>dbg!(2 + 2) * 5"#, r#"let res = (2 + 2) * 5"#);
        check_assist(remove_dbg, r#"let res = <|>dbg![2 + 2] * 5"#, r#"let res = (2 + 2) * 5"#);
    }

    #[test]
    fn test_remove_dbg_from_inside_fn() {
        check_assist_target(
            remove_dbg,
            r#"
fn square(x: u32) -> u32 {
    x * x
}

fn main() {
    let x = square(dbg<|>!(5 + 10));
    println!("{}", x);
}"#,
            "dbg!(5 + 10)",
        );

        check_assist(
            remove_dbg,
            r#"
fn square(x: u32) -> u32 {
    x * x
}

fn main() {
    let x = square(dbg<|>!(5 + 10));
    println!("{}", x);
}"#,
            r#"
fn square(x: u32) -> u32 {
    x * x
}

fn main() {
    let x = square(5 + 10);
    println!("{}", x);
}"#,
        );
    }
}
<|endoftext|>


<commit_before>//! Types for the `m.room.join_rules` event.

use ruma_events_macros::EventContent;
#[cfg(feature = "unstable-pre-spec")]
use ruma_identifiers::RoomId;
#[cfg(feature = "unstable-pre-spec")]
use serde::de::DeserializeOwned;
use serde::{
    de::{Deserializer, Error},
    Deserialize, Serialize,
};
use serde_json::value::RawValue as RawJsonValue;
#[cfg(feature = "unstable-pre-spec")]
use serde_json::Value as JsonValue;
use std::borrow::Cow;
#[cfg(feature = "unstable-pre-spec")]
use std::collections::BTreeMap;

/// The content of an `m.room.join_rules` event.
///
/// Describes how users are allowed to join the room.
#[derive(Clone, Debug, Serialize, EventContent)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[ruma_event(type = "m.room.join_rules", kind = State)]
pub struct RoomJoinRulesEventContent {
    /// The type of rules used for users wishing to join this room.
    #[ruma_event(skip_redaction)]
    #[serde(flatten)]
    pub join_rule: JoinRule,
}

impl RoomJoinRulesEventContent {
    /// Creates a new `RoomJoinRulesEventContent` with the given rule.
    pub fn new(join_rule: JoinRule) -> Self {
        Self { join_rule }
    }

    /// Creates a new `RoomJoinRulesEventContent` with the restricted rule and the given set of
    /// allow rules.
    #[cfg(feature = "unstable-pre-spec")]
    pub fn restricted(allow: Vec<AllowRule>) -> Self {
        Self { join_rule: JoinRule::Restricted(Restricted::new(allow)) }
    }
}

impl<'de> Deserialize<'de> for RoomJoinRulesEventContent {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        let join_rule = JoinRule::deserialize(deserializer)?;
        Ok(RoomJoinRulesEventContent { join_rule })
    }
}

/// The rule used for users wishing to join this room.
///
/// This type can hold an arbitrary string. To check for formats that are not available as a
/// documented variant here, use its string representation, obtained through `.as_str()`.
#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[serde(tag = "join_rule")]
pub enum JoinRule {
    /// A user who wishes to join the room must first receive an invite to the room from someone
    /// already inside of the room.
    #[serde(rename = "invite")]
    Invite,

    /// Reserved but not yet implemented by the Matrix specification.
    #[serde(rename = "knock")]
    Knock,

    /// Reserved but not yet implemented by the Matrix specification.
    #[serde(rename = "private")]
    Private,

    /// Users can join the room if they are invited, or if they meet any of the conditions
    /// described in a set of [`AllowRule`]s.
    #[cfg(feature = "unstable-pre-spec")]
    #[serde(rename = "restricted")]
    Restricted(Restricted),

    /// Anyone can join the room without any prior action.
    #[serde(rename = "public")]
    Public,

    #[doc(hidden)]
    #[serde(skip_serializing)]
    _Custom(String),
}

impl JoinRule {
    /// Returns the string name of this `JoinRule`
    pub fn as_str(&self) -> &str {
        match self {
            JoinRule::Invite => "invite",
            JoinRule::Knock => "knock",
            JoinRule::Private => "private",
            #[cfg(feature = "unstable-pre-spec")]
            JoinRule::Restricted(_) => "restricted",
            JoinRule::Public => "public",
            JoinRule::_Custom(rule) => rule,
        }
    }
}

impl<'de> Deserialize<'de> for JoinRule {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        #[cfg(feature = "unstable-pre-spec")]
        fn from_raw_json_value<T: DeserializeOwned, E: Error>(raw: &RawJsonValue) -> Result<T, E> {
            serde_json::from_str(raw.get()).map_err(E::custom)
        }

        let json: Box<RawJsonValue> = Box::deserialize(deserializer)?;

        #[derive(Deserialize)]
        struct ExtractType<'a> {
            join_rule: Option<Cow<'a, str>>,
        }

        let join_rule = serde_json::from_str::<ExtractType<'_>>(json.get())
            .map_err(serde::de::Error::custom)?
            .join_rule
            .ok_or_else(|| D::Error::missing_field("join_rule"))?;

        match join_rule.as_ref() {
            "invite" => Ok(Self::Invite),
            "knock" => Ok(Self::Knock),
            "private" => Ok(Self::Private),
            #[cfg(feature = "unstable-pre-spec")]
            "restricted" => from_raw_json_value(&json).map(Self::Restricted),
            "public" => Ok(Self::Public),
            _ => Ok(Self::_Custom(join_rule.into_owned())),
        }
    }
}

/// Configuration of the `Restricted` join rule.
#[cfg(feature = "unstable-pre-spec")]
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct Restricted {
    /// Allow rules which describe conditions that allow joining a room.
    allow: Vec<AllowRule>,
}

#[cfg(feature = "unstable-pre-spec")]
impl Restricted {
    /// Constructs a new rule set for restricted rooms with the given rules.
    pub fn new(allow: Vec<AllowRule>) -> Self {
        Self { allow }
    }
}

/// An allow rule which defines a condition that allows joining a room.
#[cfg(feature = "unstable-pre-spec")]
#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[serde(tag = "type")]
pub enum AllowRule {
    /// Joining is allowed if a user is already a member of the romm with the id `room_id`.
    #[serde(rename = "m.room_membership")]
    RoomMembership(RoomMembership),

    #[doc(hidden)]
    _Custom(CustomAllowRule),
}

#[cfg(feature = "unstable-pre-spec")]
impl AllowRule {
    /// Constructs an `AllowRule` with membership of the room with the given id as its predicate.
    pub fn room_membership(room_id: RoomId) -> Self {
        Self::RoomMembership(RoomMembership::new(room_id))
    }
}

/// Allow rule which grants permission to join based on the membership of another room.
#[cfg(feature = "unstable-pre-spec")]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct RoomMembership {
    /// The id of the room which being a member of grants permission to join another room.
    pub room_id: RoomId,
}

#[cfg(feature = "unstable-pre-spec")]
impl RoomMembership {
    /// Constructs a new room membership rule for the given room id.
    pub fn new(room_id: RoomId) -> Self {
        Self { room_id }
    }
}

#[cfg(feature = "unstable-pre-spec")]
#[doc(hidden)]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct CustomAllowRule {
    #[serde(rename = "type")]
    rule_type: String,
    #[serde(flatten)]
    extra: BTreeMap<String, JsonValue>,
}

#[cfg(feature = "unstable-pre-spec")]
impl<'de> Deserialize<'de> for AllowRule {
    fn deserialize<D>(deserializer: D) -> Result<AllowRule, D::Error>
    where
        D: Deserializer<'de>,
    {
        fn from_raw_json_value<T: DeserializeOwned, E: Error>(raw: &RawJsonValue) -> Result<T, E> {
            serde_json::from_str(raw.get()).map_err(E::custom)
        }

        let json: Box<RawJsonValue> = Box::deserialize(deserializer)?;

        // Extracts the `type` value.
        #[derive(Deserialize)]
        struct ExtractType<'a> {
            #[serde(borrow, rename = "type")]
            rule_type: Option<Cow<'a, str>>,
        }

        // Get the value of `type` if present.
        let rule_type = serde_json::from_str::<ExtractType<'_>>(json.get())
            .map_err(serde::de::Error::custom)?
            .rule_type;

        match rule_type.as_deref() {
            Some("m.room_membership") => from_raw_json_value(&json).map(Self::RoomMembership),
            Some(_) => from_raw_json_value(&json).map(Self::_Custom),
            None => Err(D::Error::missing_field("type")),
        }
    }
}

#[cfg(test)]
mod tests {
    use matches::assert_matches;
    #[cfg(feature = "unstable-pre-spec")]
    use ruma_identifiers::room_id;

    #[cfg(feature = "unstable-pre-spec")]
    use super::AllowRule;
    use super::{JoinRule, RoomJoinRulesEvent, RoomJoinRulesEventContent};

    #[test]
    fn deserialize() {
        let json = r#"{"join_rule": "public"}"#;
        let event: RoomJoinRulesEventContent = serde_json::from_str(json).unwrap();
        assert_matches!(event, RoomJoinRulesEventContent { join_rule: JoinRule::Public });
    }

    #[cfg(feature = "unstable-pre-spec")]
    #[test]
    fn deserialize_unstable() {
        let json = r#"{
            "join_rule": "restricted",
            "allow": [
                {
                    "type": "m.room_membership",
                    "room_id": "!mods:example.org"
                },
                {
                    "type": "m.room_membership",
                    "room_id": "!users:example.org"
                }
            ]
        }"#;
        let event: RoomJoinRulesEventContent = serde_json::from_str(json).unwrap();
        match event.join_rule {
            JoinRule::Restricted(restricted) => assert_eq!(
                restricted.allow,
                &[
                    AllowRule::room_membership(room_id!("!mods:example.org")),
                    AllowRule::room_membership(room_id!("!users:example.org"))
                ]
            ),
            rule => panic!("Deserialized to wrong variant: {:?}", rule),
        }
    }

    fn deserialize_restricted_event() {
        let json = r#"{
            "type": "m.room.join_rules",
            "sender": "@admin:community.rs",
            "content": {
                "join_rule": "restricted",
                "allow":[
                    { "type": "m.room_membership","room_id": "!KqeUnzmXPIhHRaWMTs:mccarty.io" }
                ]
            },
            "state_key": "",
            "origin_server_ts":1630508835342,
            "unsigned": {
                "age":4165521871
            },
            "event_id": "$0ACb9KSPlT3al3kikyRYvFhMqXPP9ZcQOBrsdIuh58U"
        }"#;

        assert_matches!(serde_json::from_str::<RoomJoinRulesEvent>(json), Ok(_));
    }
}
<commit_msg>events: Fix test<commit_after>//! Types for the `m.room.join_rules` event.

use ruma_events_macros::EventContent;
#[cfg(feature = "unstable-pre-spec")]
use ruma_identifiers::RoomId;
#[cfg(feature = "unstable-pre-spec")]
use serde::de::DeserializeOwned;
use serde::{
    de::{Deserializer, Error},
    Deserialize, Serialize,
};
use serde_json::value::RawValue as RawJsonValue;
#[cfg(feature = "unstable-pre-spec")]
use serde_json::Value as JsonValue;
use std::borrow::Cow;
#[cfg(feature = "unstable-pre-spec")]
use std::collections::BTreeMap;

/// The content of an `m.room.join_rules` event.
///
/// Describes how users are allowed to join the room.
#[derive(Clone, Debug, Serialize, EventContent)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[ruma_event(type = "m.room.join_rules", kind = State)]
pub struct RoomJoinRulesEventContent {
    /// The type of rules used for users wishing to join this room.
    #[ruma_event(skip_redaction)]
    #[serde(flatten)]
    pub join_rule: JoinRule,
}

impl RoomJoinRulesEventContent {
    /// Creates a new `RoomJoinRulesEventContent` with the given rule.
    pub fn new(join_rule: JoinRule) -> Self {
        Self { join_rule }
    }

    /// Creates a new `RoomJoinRulesEventContent` with the restricted rule and the given set of
    /// allow rules.
    #[cfg(feature = "unstable-pre-spec")]
    pub fn restricted(allow: Vec<AllowRule>) -> Self {
        Self { join_rule: JoinRule::Restricted(Restricted::new(allow)) }
    }
}

impl<'de> Deserialize<'de> for RoomJoinRulesEventContent {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        let join_rule = JoinRule::deserialize(deserializer)?;
        Ok(RoomJoinRulesEventContent { join_rule })
    }
}

/// The rule used for users wishing to join this room.
///
/// This type can hold an arbitrary string. To check for formats that are not available as a
/// documented variant here, use its string representation, obtained through `.as_str()`.
#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[serde(tag = "join_rule")]
pub enum JoinRule {
    /// A user who wishes to join the room must first receive an invite to the room from someone
    /// already inside of the room.
    #[serde(rename = "invite")]
    Invite,

    /// Reserved but not yet implemented by the Matrix specification.
    #[serde(rename = "knock")]
    Knock,

    /// Reserved but not yet implemented by the Matrix specification.
    #[serde(rename = "private")]
    Private,

    /// Users can join the room if they are invited, or if they meet any of the conditions
    /// described in a set of [`AllowRule`]s.
    #[cfg(feature = "unstable-pre-spec")]
    #[serde(rename = "restricted")]
    Restricted(Restricted),

    /// Anyone can join the room without any prior action.
    #[serde(rename = "public")]
    Public,

    #[doc(hidden)]
    #[serde(skip_serializing)]
    _Custom(String),
}

impl JoinRule {
    /// Returns the string name of this `JoinRule`
    pub fn as_str(&self) -> &str {
        match self {
            JoinRule::Invite => "invite",
            JoinRule::Knock => "knock",
            JoinRule::Private => "private",
            #[cfg(feature = "unstable-pre-spec")]
            JoinRule::Restricted(_) => "restricted",
            JoinRule::Public => "public",
            JoinRule::_Custom(rule) => rule,
        }
    }
}

impl<'de> Deserialize<'de> for JoinRule {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        #[cfg(feature = "unstable-pre-spec")]
        fn from_raw_json_value<T: DeserializeOwned, E: Error>(raw: &RawJsonValue) -> Result<T, E> {
            serde_json::from_str(raw.get()).map_err(E::custom)
        }

        let json: Box<RawJsonValue> = Box::deserialize(deserializer)?;

        #[derive(Deserialize)]
        struct ExtractType<'a> {
            join_rule: Option<Cow<'a, str>>,
        }

        let join_rule = serde_json::from_str::<ExtractType<'_>>(json.get())
            .map_err(serde::de::Error::custom)?
            .join_rule
            .ok_or_else(|| D::Error::missing_field("join_rule"))?;

        match join_rule.as_ref() {
            "invite" => Ok(Self::Invite),
            "knock" => Ok(Self::Knock),
            "private" => Ok(Self::Private),
            #[cfg(feature = "unstable-pre-spec")]
            "restricted" => from_raw_json_value(&json).map(Self::Restricted),
            "public" => Ok(Self::Public),
            _ => Ok(Self::_Custom(join_rule.into_owned())),
        }
    }
}

/// Configuration of the `Restricted` join rule.
#[cfg(feature = "unstable-pre-spec")]
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct Restricted {
    /// Allow rules which describe conditions that allow joining a room.
    allow: Vec<AllowRule>,
}

#[cfg(feature = "unstable-pre-spec")]
impl Restricted {
    /// Constructs a new rule set for restricted rooms with the given rules.
    pub fn new(allow: Vec<AllowRule>) -> Self {
        Self { allow }
    }
}

/// An allow rule which defines a condition that allows joining a room.
#[cfg(feature = "unstable-pre-spec")]
#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[serde(tag = "type")]
pub enum AllowRule {
    /// Joining is allowed if a user is already a member of the romm with the id `room_id`.
    #[serde(rename = "m.room_membership")]
    RoomMembership(RoomMembership),

    #[doc(hidden)]
    _Custom(CustomAllowRule),
}

#[cfg(feature = "unstable-pre-spec")]
impl AllowRule {
    /// Constructs an `AllowRule` with membership of the room with the given id as its predicate.
    pub fn room_membership(room_id: RoomId) -> Self {
        Self::RoomMembership(RoomMembership::new(room_id))
    }
}

/// Allow rule which grants permission to join based on the membership of another room.
#[cfg(feature = "unstable-pre-spec")]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct RoomMembership {
    /// The id of the room which being a member of grants permission to join another room.
    pub room_id: RoomId,
}

#[cfg(feature = "unstable-pre-spec")]
impl RoomMembership {
    /// Constructs a new room membership rule for the given room id.
    pub fn new(room_id: RoomId) -> Self {
        Self { room_id }
    }
}

#[cfg(feature = "unstable-pre-spec")]
#[doc(hidden)]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct CustomAllowRule {
    #[serde(rename = "type")]
    rule_type: String,
    #[serde(flatten)]
    extra: BTreeMap<String, JsonValue>,
}

#[cfg(feature = "unstable-pre-spec")]
impl<'de> Deserialize<'de> for AllowRule {
    fn deserialize<D>(deserializer: D) -> Result<AllowRule, D::Error>
    where
        D: Deserializer<'de>,
    {
        fn from_raw_json_value<T: DeserializeOwned, E: Error>(raw: &RawJsonValue) -> Result<T, E> {
            serde_json::from_str(raw.get()).map_err(E::custom)
        }

        let json: Box<RawJsonValue> = Box::deserialize(deserializer)?;

        // Extracts the `type` value.
        #[derive(Deserialize)]
        struct ExtractType<'a> {
            #[serde(borrow, rename = "type")]
            rule_type: Option<Cow<'a, str>>,
        }

        // Get the value of `type` if present.
        let rule_type = serde_json::from_str::<ExtractType<'_>>(json.get())
            .map_err(serde::de::Error::custom)?
            .rule_type;

        match rule_type.as_deref() {
            Some("m.room_membership") => from_raw_json_value(&json).map(Self::RoomMembership),
            Some(_) => from_raw_json_value(&json).map(Self::_Custom),
            None => Err(D::Error::missing_field("type")),
        }
    }
}

#[cfg(test)]
mod tests {
    use matches::assert_matches;
    #[cfg(feature = "unstable-pre-spec")]
    use ruma_identifiers::room_id;

    #[cfg(feature = "unstable-pre-spec")]
    use super::AllowRule;
    use super::{JoinRule, RoomJoinRulesEventContent, SyncRoomJoinRulesEvent};

    #[test]
    fn deserialize() {
        let json = r#"{"join_rule": "public"}"#;
        let event: RoomJoinRulesEventContent = serde_json::from_str(json).unwrap();
        assert_matches!(event, RoomJoinRulesEventContent { join_rule: JoinRule::Public });
    }

    #[cfg(feature = "unstable-pre-spec")]
    #[test]
    fn deserialize_unstable() {
        let json = r#"{
            "join_rule": "restricted",
            "allow": [
                {
                    "type": "m.room_membership",
                    "room_id": "!mods:example.org"
                },
                {
                    "type": "m.room_membership",
                    "room_id": "!users:example.org"
                }
            ]
        }"#;
        let event: RoomJoinRulesEventContent = serde_json::from_str(json).unwrap();
        match event.join_rule {
            JoinRule::Restricted(restricted) => assert_eq!(
                restricted.allow,
                &[
                    AllowRule::room_membership(room_id!("!mods:example.org")),
                    AllowRule::room_membership(room_id!("!users:example.org"))
                ]
            ),
            rule => panic!("Deserialized to wrong variant: {:?}", rule),
        }
    }

    #[test]
    fn deserialize_restricted_event() {
        let json = r#"{
            "type": "m.room.join_rules",
            "sender": "@admin:community.rs",
            "content": {
                "join_rule": "restricted",
                "allow":[
                    { "type": "m.room_membership","room_id": "!KqeUnzmXPIhHRaWMTs:mccarty.io" }
                ]
            },
            "state_key": "",
            "origin_server_ts":1630508835342,
            "unsigned": {
                "age":4165521871
            },
            "event_id": "$0ACb9KSPlT3al3kikyRYvFhMqXPP9ZcQOBrsdIuh58U"
        }"#;

        assert_matches!(serde_json::from_str::<SyncRoomJoinRulesEvent>(json), Ok(_));
    }
}
<|endoftext|>


<commit_before>use fst::raw::FstData as ReadOnlySource;
use std::io::BufWriter;
use std::io;
use fst::raw::SharedVectorSlice;
use std::io::Write;
use std::fs::File;
use std::fmt;
use std::collections::HashMap;
use std::collections::hash_map::Entry as HashMapEntry;
use fst::raw::MmapReadOnly;
use atomicwrites;
use tempdir::TempDir;
use std::cell::RefCell;
use std::path::{Path, PathBuf};

pub enum CreateError {
    RootDirectoryDoesNotExist,
    DirectoryAlreadyExists,
    CannotCreateTempDirectory(io::Error),
}

pub trait Directory: fmt::Debug {
    fn open_read<P: AsRef<Path>>(&self, path: P) -> io::Result<ReadOnlySource>;
    fn open_write<P: AsRef<Path>>(&mut self, path: P) -> io::Result<Box<Write>>;
    fn atomic_write<P: AsRef<Path>>(&mut self, path: P, data: &[u8]) -> io::Result<()>;
}

////////////////////////////////////////////////////////////////
// MmapDirectory

pub struct MmapDirectory {
    root_path: PathBuf,
    mmap_cache: RefCell<HashMap<PathBuf, MmapReadOnly>>,
    _temp_directory: Option<TempDir>,
}

impl fmt::Debug for MmapDirectory {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
       write!(f, "MmapDirectory({:?})", self.root_path)
   }
}

impl MmapDirectory {

    pub fn create_tempdir() -> Result<MmapDirectory, CreateError> {
        // TODO error management
        let tempdir = try!(TempDir::new("index").map_err(CreateError::CannotCreateTempDirectory));
        let tempdir_path = PathBuf::from(tempdir.path());
        let mut directory = MmapDirectory {
            root_path: PathBuf::from(tempdir_path),
            mmap_cache: RefCell::new(HashMap::new()),
            _temp_directory: Some(tempdir)
        };
        Ok(directory)
    }

    pub fn create<P: AsRef<Path>>(filepath: P) -> Result<MmapDirectory, CreateError> {
        Ok(MmapDirectory {
            root_path: PathBuf::from(filepath.as_ref()),
            mmap_cache: RefCell::new(HashMap::new()),
            _temp_directory: None
        })
    }

    fn resolve_path<P: AsRef<Path>>(&self, relative_path: P) -> PathBuf {
        self.root_path.join(relative_path)
    }
}

impl Directory for MmapDirectory {
    fn open_read<P: AsRef<Path>>(&self, path: P) -> io::Result<ReadOnlySource> {
        let full_path = self.resolve_path(path);
        let mut mmap_cache = self.mmap_cache.borrow_mut();
        let mmap = match mmap_cache.entry(full_path.clone()) {
            HashMapEntry::Occupied(e) => e.get().clone(),
            HashMapEntry::Vacant(vacant_entry) => {
                let new_mmap =  try!(MmapReadOnly::open_path(full_path.clone()));
                vacant_entry.insert(new_mmap.clone());
                new_mmap
            }
        };
        Ok(ReadOnlySource::Mmap(mmap))
    }
    fn open_write<P: AsRef<Path>>(&mut self, path: P) -> io::Result<Box<Write>> {
        let full_path = self.resolve_path(path);
        let file = try!(File::create(full_path));
        Ok(Box::new(file))
    }

    fn atomic_write<P: AsRef<Path>>(&mut self, path: P, data: &[u8]) -> io::Result<()> {
        let full_path = self.resolve_path(path);
        let meta_file = atomicwrites::AtomicFile::new(full_path, atomicwrites::AllowOverwrite);
        meta_file.write(|f| {
            f.write_all(data)
        });
        Ok(())
    }
}

////////////////////////////////////////////////////////////////
// RAMDirectory

pub struct RAMDirectory {
    fs: RefCell<HashMap<PathBuf, SharedVectorSlice>>,
}

impl fmt::Debug for RAMDirectory {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
       write!(f, "RAMDirectory")
   }
}

impl RAMDirectory {

    pub fn create() -> Result<RAMDirectory, CreateError> {
        Ok(RAMDirectory {
            fs: RefCell::new(HashMap::new())
        })
    }
}

impl Directory for RAMDirectory {
    fn open_read<P: AsRef<Path>>(&self, path: P) -> io::Result<ReadOnlySource> {
        // let full_path = PathBuf::from(path);
        match self.fs.borrow().get(path.as_ref()) {
            Some(data) => Ok(ReadOnlySource::SharedVector(*data.clone())),
            None => Err(io::Error::new(io::ErrorKind::NotFound, "File has never been created."))
        }
        // Ok(ReadOnlySource::Mmap(mmap))
    }
    fn open_write<P: AsRef<Path>>(&mut self, path: P) -> io::Result<Box<Write>> {
        let full_path = PathBuf::from(path);
        let data = SharedVectorSlice::from(Vec::new());
        self.fs.borrow_mut().insert(full_path, data.clone());
        Ok(Box::new(data))
    }

    fn atomic_write<P: AsRef<Path>>(&mut self, path: P, data: &[u8]) -> io::Result<()> {
        let full_path = self.resolve_path(path);
        let meta_file = atomicwrites::AtomicFile::new(full_path, atomicwrites::AllowOverwrite);
        meta_file.write(|f| {
            f.write_all(data)
        });
        Ok(())
    }
}
<commit_msg>directory2 working.<commit_after>use std::io::BufWriter;
use std::io;
use fst::raw::SharedVectorSlice;
use std::fmt::Arguments;
use std::io::Write;
use std::fs::File;
use std::fmt;
use std::collections::HashMap;
use std::collections::hash_map::Entry as HashMapEntry;
use fst::raw::MmapReadOnly;
use atomicwrites;
use std::sync::Arc;
use std::sync::RwLock;
use std::rc::Rc;
use tempdir::TempDir;
use std::cell::RefCell;
use std::ops::Deref;
use std::path::{Path, PathBuf};

///////////////////////////////////////////////////////////////
//

pub enum ReadOnlySource {
    Mmap(MmapReadOnly),
    Anonymous(Vec<u8>),
}

impl Deref for ReadOnlySource {
    type Target = [u8];

    fn deref(&self) -> &[u8] {
        match *self {
            ReadOnlySource::Mmap(ref mmap_read_only) => unsafe { mmap_read_only.as_slice() },
            ReadOnlySource::Anonymous(ref shared_vec) => shared_vec.as_slice(),
        }
    }
}

#[derive(Debug)]
pub enum CreateError {
    RootDirectoryDoesNotExist,
    DirectoryAlreadyExists,
    CannotCreateTempDirectory(io::Error),
}

pub trait Directory: fmt::Debug {
    fn open_read(&self, path: &Path) -> io::Result<ReadOnlySource>;
    fn open_write(&mut self, path: &Path) -> io::Result<Box<Write>>;
    fn atomic_write(&mut self, path: &Path, data: &[u8]) -> io::Result<()>;
}

pub type WritePtr = Box<Write>;

////////////////////////////////////////////////////////////////
// MmapDirectory

pub struct MmapDirectory {
    root_path: PathBuf,
    mmap_cache: RefCell<HashMap<PathBuf, MmapReadOnly>>,
    _temp_directory: Option<TempDir>,
}

impl fmt::Debug for MmapDirectory {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
       write!(f, "MmapDirectory({:?})", self.root_path)
   }
}

impl MmapDirectory {

    pub fn create_tempdir() -> Result<MmapDirectory, CreateError> {
        // TODO error management
        let tempdir = try!(TempDir::new("index").map_err(CreateError::CannotCreateTempDirectory));
        let tempdir_path = PathBuf::from(tempdir.path());
        let mut directory = MmapDirectory {
            root_path: PathBuf::from(tempdir_path),
            mmap_cache: RefCell::new(HashMap::new()),
            _temp_directory: Some(tempdir)
        };
        Ok(directory)
    }

    pub fn create(filepath: &Path) -> Result<MmapDirectory, CreateError> {
        Ok(MmapDirectory {

            root_path: PathBuf::from(filepath),
            mmap_cache: RefCell::new(HashMap::new()),
            _temp_directory: None
        })
    }

    fn resolve_path(&self, relative_path: &Path) -> PathBuf {
        self.root_path.join(relative_path)
    }
}

impl Directory for MmapDirectory {
    fn open_read(&self, path: &Path) -> io::Result<ReadOnlySource> {
        let full_path = self.resolve_path(path);
        let mut mmap_cache = self.mmap_cache.borrow_mut();
        let mmap = match mmap_cache.entry(full_path.clone()) {
            HashMapEntry::Occupied(e) => e.get().clone(),
            HashMapEntry::Vacant(vacant_entry) => {
                let new_mmap =  try!(MmapReadOnly::open_path(full_path.clone()));
                vacant_entry.insert(new_mmap.clone());
                new_mmap
            }
        };
        Ok(ReadOnlySource::Mmap(mmap))
    }
    fn open_write(&mut self, path: &Path) -> io::Result<WritePtr> {
        let full_path = self.resolve_path(path);
        let file = try!(File::create(full_path));
        Ok(Box::new(file))
    }

    fn atomic_write(&mut self, path: &Path, data: &[u8]) -> io::Result<()> {
        let full_path = self.resolve_path(path);
        let meta_file = atomicwrites::AtomicFile::new(full_path, atomicwrites::AllowOverwrite);
        meta_file.write(|f| {
            f.write_all(data)
        });
        Ok(())
    }
}

////////////////////////////////////////////////////////////////
// RAMDirectory

#[derive(Clone)]
struct SharedVec(Arc<RwLock<Vec<u8>>>);

pub struct RAMDirectory {
    fs: HashMap<PathBuf, SharedVec>,
}

impl SharedVec {
    fn new() -> SharedVec {
        SharedVec(Arc::new( RwLock::new(Vec::new()) ))
    }
}

impl Write for SharedVec {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.0.write().unwrap().write(buf);
        Ok(buf.len())
    }
    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

impl fmt::Debug for RAMDirectory {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
       write!(f, "RAMDirectory")
   }
}

impl RAMDirectory {
    pub fn create() -> Result<RAMDirectory, CreateError> {
        Ok(RAMDirectory {
            fs: HashMap::new()
        })
    }
}

impl Directory for RAMDirectory {
    fn open_read(&self, path: &Path) -> io::Result<ReadOnlySource> {
        match self.fs.get(path) {
            Some(ref data) => {
                let data_copy = (*data).0.read().unwrap().clone();
                Ok(ReadOnlySource::Anonymous(data_copy))
            },
            None =>
                Err(io::Error::new(io::ErrorKind::NotFound, "File has never been created."))
        }
    }
    fn open_write(&mut self, path: &Path) -> io::Result<WritePtr> {
        let full_path = PathBuf::from(&path);
        let mut data = SharedVec::new();
        self.fs.insert(full_path, data.clone());
        Ok(Box::new(data))
    }

    fn atomic_write(&mut self, path: &Path, data: &[u8]) -> io::Result<()> {
        let meta_file = atomicwrites::AtomicFile::new(PathBuf::from(path), atomicwrites::AllowOverwrite);
        meta_file.write(|f| {
            f.write_all(data)
        });
        Ok(())
    }
}

#[cfg(test)]
mod tests {

    use super::*;
    use test::Bencher;
    use core::schema::DocId;
    use std::path::Path;

    #[test]
    fn test_ram_directory() {
        let mut ram_directory = RAMDirectory::create().unwrap();
        test_directory(&mut ram_directory);
    }

    #[test]
    fn test_mmap_directory() {
        let mut mmap_directory = MmapDirectory::create_tempdir().unwrap();
        test_directory(&mut mmap_directory);
    }

    fn test_directory(directory: &mut Directory) {
        {
            let mut write_file = directory.open_write(Path::new("toto")).unwrap();
            write_file.write_all(&[4]);
            write_file.write_all(&[3]);
            write_file.write_all(&[7,3,5]);
        }
        let read_file = directory.open_read(Path::new("toto")).unwrap();
        let data: &[u8] = &*read_file;
        assert_eq!(data.len(), 5);
        assert_eq!(data[0], 4);
        assert_eq!(data[1], 3);
        assert_eq!(data[2], 7);
        assert_eq!(data[3], 3);
        assert_eq!(data[4], 5);
    }

}
<|endoftext|>


<commit_before>use std::ffi::CString;

use rustc::lib::llvm;
use rustc::lib::llvm::{ ContextRef
                      , ModuleRef
                      , ValueRef
                  };
use seax::compiler_tools::ForkTable;

use position::Positional;

pub type IRResult = Result<ValueRef, Positional<String>>;
pub type SymbolTable<'a> = ForkTable<'a, &'a str, ValueRef>;

/// Trait for an object that can be compiled to LLVM IR
pub trait ToIR {
    fn to_ir(&self) -> IRResult;
}

/// LLVM compilation context.
///
/// This is based rather loosely on MIT License code from
/// the [iron-kaleidoscope](https://github.com/jauhien/iron-kaleidoscope)
/// tutorial, and from [`librustc_trans`](https://github.com/rust-lang/rust/blob/master/src/librustc_trans/trans/mod.rs)
/// from the Rust compiler.
pub struct LLVMContext<'a> {
    pub llctx: ContextRef,
    pub llmod: ModuleRef,
    pub names: SymbolTable<'a>
}

// because we are in the Raw Pointer Sadness Zone (read: unsafe),
// it is necessary that we assert that everything exists.
macro_rules! not_null {
    ($target:expr) => ({
        let e = $target;
        if e.is_null() {
            panic!("assertion failed: {} returned null!", stringify!($target));
        } else { e }
    })
}

impl<'a> LLVMContext<'a> {
    pub fn new(module_name: &str) -> Self {
        let name = CString::new(module_name).unwrap();
        unsafe {
            let c = not_null!(llvm::LLVMContextCreate());
            let m = not_null!(
                llvm::LLVMModuleCreateWithNameInContext(name.into_raw(),c)
                );
            LLVMContext { llctx: c
                        , llmod: m
                        , names: SymbolTable::new()
                    }
        }
    }
}

impl<'a> Drop for LLVMContext<'a> {
    fn drop(&mut self) {
        unsafe {
            llvm::LLVMDisposeModule(self.llmod);
            llvm::LLVMContextDispose(self.llctx);
        }
    }
}
<commit_msg>Add LLVM builder to LLVMContext<commit_after>use std::ffi::CString;

use rustc::lib::llvm;
use rustc::lib::llvm::{ ContextRef
                      , ModuleRef
                      , ValueRef
                      , BuilderRef
                  };
use seax::compiler_tools::ForkTable;

use position::Positional;

pub type IRResult = Result<ValueRef, Positional<String>>;
pub type SymbolTable<'a> = ForkTable<'a, &'a str, ValueRef>;

/// Trait for an object that can be compiled to LLVM IR
pub trait ToIR {
    fn to_ir(&self) -> IRResult;
}

/// LLVM compilation context.
///
/// This is based rather loosely on MIT License code from
/// the [iron-kaleidoscope](https://github.com/jauhien/iron-kaleidoscope)
/// tutorial, and from [`librustc_trans`](https://github.com/rust-lang/rust/blob/master/src/librustc_trans/trans/mod.rs)
/// from the Rust compiler.
pub struct LLVMContext<'a> {
    pub llctx: ContextRef,
    pub llmod: ModuleRef,
    pub llbuilder: BuilderRef,
    pub names: SymbolTable<'a>
}

// because we are in the Raw Pointer Sadness Zone (read: unsafe),
// it is necessary that we assert that everything exists.
macro_rules! not_null {
    ($target:expr) => ({
        let e = $target;
        if e.is_null() {
            panic!("assertion failed: {} returned null!", stringify!($target));
        } else { e }
    })
}

impl<'a> LLVMContext<'a> {
    pub fn new(module_name: &str) -> Self {
        let name = CString::new(module_name).unwrap();
        unsafe {
            let ctx = not_null!(llvm::LLVMContextCreate());
            LLVMContext {
                llctx: ctx
              , llmod: not_null!(llvm::LLVMModuleCreateWithNameInContext(name.into_raw(), ctx))
              , llbuilder: not_null!(llvm::LLVMCreateBuilderInContext(ctx))
              , names: SymbolTable::new()
            }
        }
    }
}

impl<'a> Drop for LLVMContext<'a> {
    fn drop(&mut self) {
        unsafe {
            llvm::LLVMDisposeModule(self.llmod);
            llvm::LLVMDisposeBuilder(self.llbuilder);
            llvm::LLVMContextDispose(self.llctx);
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2015-2016 Robert Clipsham <robert@octarineparrot.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Support for sending and receiving data link layer packets using the netmap library

#![allow(bad_style)]

extern crate netmap_sys;
extern crate libc;

use self::netmap_sys::netmap_user::{NETMAP_BUF, NETMAP_FD, NETMAP_TXRING, nm_close, nm_desc,
                                    nm_nextpkt, nm_open, nm_pkthdr, nm_ring_next};
use self::netmap_sys::netmap::{netmap_slot, nm_ring_empty};

use std::ffi::CString;
use std::path::Path;
use std::fs::File;
use std::io;
use std::io::Read;
use std::mem;
use std::ptr;
use std::slice;
use std::sync::Arc;

use datalink::{self, NetworkInterface};
use datalink::Channel::Ethernet;
use datalink::{EthernetDataLinkChannelIterator, EthernetDataLinkReceiver, EthernetDataLinkSender};
use packet::Packet;
use packet::ethernet::{EthernetPacket, MutableEthernetPacket};

#[cfg(any(target_os = "linux", target_os = "freebsd"))]
#[repr(C)]
struct pollfd {
    fd: libc::c_int,
    events: libc::c_short,
    revents: libc::c_short,
}

#[cfg(any(target_os = "linux", target_os = "freebsd"))]
const POLLIN: libc::c_short = 0x0001;
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
const POLLOUT: libc::c_short = 0x0004;

#[cfg(target_os = "freebsd")]
type nfds_t = libc::c_uint;
#[cfg(target_os = "linux")]
type nfds_t = libc::c_ulong;

extern {
    fn poll(fds: *mut pollfd, nfds: nfds_t, timeout: libc::c_int) -> libc::c_int;
    fn ppoll(fds: *mut pollfd, nfds: nfds_t, timeout: *const libc::timespec, newsigmask: *const libc::sigset_t) -> libc::c_int;
}

struct NmDesc {
    desc: *mut nm_desc,
    buf_size: libc::c_uint,
}

unsafe impl Send for NmDesc {}
unsafe impl Sync for NmDesc {}

impl NmDesc {
    fn new(iface: &NetworkInterface) -> io::Result<NmDesc> {
        let ifname = CString::new(("netmap:".to_owned() + &iface.name[..]).as_bytes());
        let desc = unsafe { nm_open(ifname.unwrap().as_ptr(), ptr::null(), 0, ptr::null()) };

        if desc.is_null() {
            Err(io::Error::last_os_error())
        } else {
            let mut f = try!(File::open(&Path::new("/sys/module/netmap/parameters/buf_size")));
            let mut num_str = String::new();
            try!(f.read_to_string(&mut num_str));
            let buf_size = num_str.trim_right().parse().unwrap();

            Ok(NmDesc {
                desc: desc,
                buf_size: buf_size,
            })
        }
    }
}

impl Drop for NmDesc {
    fn drop(&mut self) {
        unsafe {
            nm_close(self.desc);
        }
    }
}

/// Netmap specific configuration
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct Config {
    /// The read timeout. Defaults to None.
    pub read_timeout: Option<Duration>,

    /// The write timeout. Defaults to None.
    pub write_timeout: Option<Duration>,
}

impl<'a> From<&'a datalink::Config> for Config {
    fn from(_config: &datalink::Config) -> Config {
        Config {
            read_timeout: config.read_timeout,
            write_timeout: config.write_timeout,
        }
    }
}

impl Default for Config {
    fn default() -> Config {
        Config {
            read_timeout: None,
            write_timeout: None,
        }
    }
}

#[inline]
fn get_timeout(to: Option<Duration>) -> Option<libc::timespec> {
    to.map(|dur| {
        libc::timespec {
            tv_sec: dur.as_secs() as libc::time_t,
            tv_nsec: dur.subsec_nanos() as libc::c_long
        }
    })
}

/// Create a datalink channel using the netmap library
#[inline]
pub fn channel(network_interface: &NetworkInterface, config: Config)
    -> io::Result<datalink::Channel> {
    // FIXME probably want one for each of send/recv
    let desc = NmDesc::new(network_interface);
    match desc {
        Ok(desc) => {
            let arc = Arc::new(desc);

            Ok(Ethernet(
                Box::new(DataLinkSenderImpl {
                    desc: arc.clone(),
                    timeout: get_timeout(config.write_timeout)
                }),
                Box::new(DataLinkReceiverImpl {
                    desc: arc,
                    timeout: get_timeout(config.read_timeout)
                })))
        }
        Err(e) => Err(e),
    }
}

struct DataLinkSenderImpl {
    desc: Arc<NmDesc>,
    timeout: Option<libc::timespec>,
}

impl EthernetDataLinkSender for DataLinkSenderImpl {
    #[inline]
    fn build_and_send(&mut self,
                      num_packets: usize,
                      packet_size: usize,
                      func: &mut FnMut(MutableEthernetPacket))
        -> Option<io::Result<()>> {
        assert!(packet_size <= self.desc.buf_size as usize);
        let desc = self.desc.desc;
        let mut fds = pollfd {
            fd: unsafe { NETMAP_FD(desc) },
            events: POLLOUT,
            revents: 0,
        };
        let mut packet_idx = 0usize;
        while packet_idx < num_packets {
            unsafe {
                let timespec = self.timeout.as_ref().map(|ts| ts as *const _).unwrap_or(ptr::null());
                if ppoll(&mut fds, 1, timespec, ptr::null()) < 0 {
                    return Some(Err(io::Error::last_os_error()));
                }
                let ring = NETMAP_TXRING((*desc).nifp, 0);
                while !nm_ring_empty(ring) && packet_idx < num_packets {
                    let i = (*ring).cur;
                    let slot_ptr: *mut netmap_slot = mem::transmute(&mut (*ring).slot);
                    let buf = NETMAP_BUF(ring, (*slot_ptr.offset(i as isize)).buf_idx as isize);
                    let slice = slice::from_raw_parts_mut(buf as *mut u8, packet_size);
                    let meh = MutableEthernetPacket::new(slice).unwrap();
                    (*slot_ptr.offset(i as isize)).len = packet_size as u16;
                    func(meh);
                    let next = nm_ring_next(ring, i);
                    (*ring).head = next;
                    (*ring).cur = next;
                    packet_idx += 1;
                }
            }
        }

        Some(Ok(()))
    }

    #[inline]
    fn send_to(&mut self,
               packet: &EthernetPacket,
               _dst: Option<NetworkInterface>)
        -> Option<io::Result<()>> {
        use packet::MutablePacket;
        self.build_and_send(1,
                            packet.packet().len(),
                            &mut |mut eh: MutableEthernetPacket| {
                                eh.clone_from(packet);
                            })
    }
}

struct DataLinkReceiverImpl {
    desc: Arc<NmDesc>,
    timeout: Option<libc::timespec>,
}

impl EthernetDataLinkReceiver for DataLinkReceiverImpl {
    // FIXME Layer 3
    fn iter<'a>(&'a mut self) -> Box<EthernetDataLinkChannelIterator + 'a> {
        Box::new(DataLinkChannelIteratorImpl { pc: self })
    }
}

struct DataLinkChannelIteratorImpl<'a> {
    pc: &'a mut DataLinkReceiverImpl,
}

impl<'a> EthernetDataLinkChannelIterator<'a> for DataLinkChannelIteratorImpl<'a> {
    fn next(&mut self) -> io::Result<EthernetPacket> {
        let desc = self.pc.desc.desc;
        let mut h: nm_pkthdr = unsafe { mem::uninitialized() };
        let mut buf = unsafe { nm_nextpkt(desc, &mut h) };
        if buf.is_null() {
            let mut fds = pollfd {
                fd: unsafe { NETMAP_FD(desc) },
                events: POLLIN,
                revents: 0,
            };
            let timespec = self.timeout.as_ref().map(|ts| ts as *const _).unwrap_or(ptr::null());
            if unsafe { ppoll(&mut fds, 1, timespec, ptr::null()) } < 0 {
                return Err(io::Error::last_os_error());
            }
            buf = unsafe { nm_nextpkt(desc, &mut h) };
        }
        Ok(EthernetPacket::new(unsafe {
            slice::from_raw_parts(buf, h.len as usize)
        }).unwrap())
    }
}

/// Get a list of available network interfaces for the current machine.
pub fn interfaces() -> Vec<NetworkInterface> {
    #[path = "unix_interfaces.rs"]
    mod interfaces;
    interfaces::interfaces()
}
<commit_msg>fix netmap build<commit_after>// Copyright (c) 2015-2016 Robert Clipsham <robert@octarineparrot.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Support for sending and receiving data link layer packets using the netmap library

#![allow(bad_style)]

extern crate netmap_sys;
extern crate libc;

use self::netmap_sys::netmap_user::{NETMAP_BUF, NETMAP_FD, NETMAP_TXRING, nm_close, nm_desc,
                                    nm_nextpkt, nm_open, nm_pkthdr, nm_ring_next};
use self::netmap_sys::netmap::{netmap_slot, nm_ring_empty};

use std::ffi::CString;
use std::path::Path;
use std::fs::File;
use std::io;
use std::io::Read;
use std::mem;
use std::ptr;
use std::slice;
use std::sync::Arc;
use std::time::Duration;

use datalink::{self, NetworkInterface};
use datalink::Channel::Ethernet;
use datalink::{EthernetDataLinkChannelIterator, EthernetDataLinkReceiver, EthernetDataLinkSender};
use packet::Packet;
use packet::ethernet::{EthernetPacket, MutableEthernetPacket};

#[cfg(any(target_os = "linux", target_os = "freebsd"))]
#[repr(C)]
struct pollfd {
    fd: libc::c_int,
    events: libc::c_short,
    revents: libc::c_short,
}

#[cfg(any(target_os = "linux", target_os = "freebsd"))]
const POLLIN: libc::c_short = 0x0001;
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
const POLLOUT: libc::c_short = 0x0004;

#[cfg(target_os = "freebsd")]
type nfds_t = libc::c_uint;
#[cfg(target_os = "linux")]
type nfds_t = libc::c_ulong;

extern {
    fn poll(fds: *mut pollfd, nfds: nfds_t, timeout: libc::c_int) -> libc::c_int;
    fn ppoll(fds: *mut pollfd, nfds: nfds_t, timeout: *const libc::timespec, newsigmask: *const libc::sigset_t) -> libc::c_int;
}

struct NmDesc {
    desc: *mut nm_desc,
    buf_size: libc::c_uint,
}

unsafe impl Send for NmDesc {}
unsafe impl Sync for NmDesc {}

impl NmDesc {
    fn new(iface: &NetworkInterface) -> io::Result<NmDesc> {
        let ifname = CString::new(("netmap:".to_owned() + &iface.name[..]).as_bytes());
        let desc = unsafe { nm_open(ifname.unwrap().as_ptr(), ptr::null(), 0, ptr::null()) };

        if desc.is_null() {
            Err(io::Error::last_os_error())
        } else {
            let mut f = try!(File::open(&Path::new("/sys/module/netmap/parameters/buf_size")));
            let mut num_str = String::new();
            try!(f.read_to_string(&mut num_str));
            let buf_size = num_str.trim_right().parse().unwrap();

            Ok(NmDesc {
                desc: desc,
                buf_size: buf_size,
            })
        }
    }
}

impl Drop for NmDesc {
    fn drop(&mut self) {
        unsafe {
            nm_close(self.desc);
        }
    }
}

/// Netmap specific configuration
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct Config {
    /// The read timeout. Defaults to None.
    pub read_timeout: Option<Duration>,

    /// The write timeout. Defaults to None.
    pub write_timeout: Option<Duration>,
}

impl<'a> From<&'a datalink::Config> for Config {
    fn from(config: &datalink::Config) -> Config {
        Config {
            read_timeout: config.read_timeout,
            write_timeout: config.write_timeout,
        }
    }
}

impl Default for Config {
    fn default() -> Config {
        Config {
            read_timeout: None,
            write_timeout: None,
        }
    }
}

#[inline]
fn get_timeout(to: Option<Duration>) -> Option<libc::timespec> {
    to.map(|dur| {
        libc::timespec {
            tv_sec: dur.as_secs() as libc::time_t,
            tv_nsec: dur.subsec_nanos() as libc::c_long
        }
    })
}

/// Create a datalink channel using the netmap library
#[inline]
pub fn channel(network_interface: &NetworkInterface, config: Config)
    -> io::Result<datalink::Channel> {
    // FIXME probably want one for each of send/recv
    let desc = NmDesc::new(network_interface);
    match desc {
        Ok(desc) => {
            let arc = Arc::new(desc);

            Ok(Ethernet(
                Box::new(DataLinkSenderImpl {
                    desc: arc.clone(),
                    timeout: get_timeout(config.write_timeout)
                }),
                Box::new(DataLinkReceiverImpl {
                    desc: arc,
                    timeout: get_timeout(config.read_timeout)
                })))
        }
        Err(e) => Err(e),
    }
}

struct DataLinkSenderImpl {
    desc: Arc<NmDesc>,
    timeout: Option<libc::timespec>,
}

impl EthernetDataLinkSender for DataLinkSenderImpl {
    #[inline]
    fn build_and_send(&mut self,
                      num_packets: usize,
                      packet_size: usize,
                      func: &mut FnMut(MutableEthernetPacket))
        -> Option<io::Result<()>> {
        assert!(packet_size <= self.desc.buf_size as usize);
        let desc = self.desc.desc;
        let mut fds = pollfd {
            fd: unsafe { NETMAP_FD(desc) },
            events: POLLOUT,
            revents: 0,
        };
        let mut packet_idx = 0usize;
        while packet_idx < num_packets {
            unsafe {
                let timespec = self.timeout.as_ref().map(|ts| ts as *const _).unwrap_or(ptr::null());
                if ppoll(&mut fds, 1, timespec, ptr::null()) < 0 {
                    return Some(Err(io::Error::last_os_error()));
                }
                let ring = NETMAP_TXRING((*desc).nifp, 0);
                while !nm_ring_empty(ring) && packet_idx < num_packets {
                    let i = (*ring).cur;
                    let slot_ptr: *mut netmap_slot = mem::transmute(&mut (*ring).slot);
                    let buf = NETMAP_BUF(ring, (*slot_ptr.offset(i as isize)).buf_idx as isize);
                    let slice = slice::from_raw_parts_mut(buf as *mut u8, packet_size);
                    let meh = MutableEthernetPacket::new(slice).unwrap();
                    (*slot_ptr.offset(i as isize)).len = packet_size as u16;
                    func(meh);
                    let next = nm_ring_next(ring, i);
                    (*ring).head = next;
                    (*ring).cur = next;
                    packet_idx += 1;
                }
            }
        }

        Some(Ok(()))
    }

    #[inline]
    fn send_to(&mut self,
               packet: &EthernetPacket,
               _dst: Option<NetworkInterface>)
        -> Option<io::Result<()>> {
        use packet::MutablePacket;
        self.build_and_send(1,
                            packet.packet().len(),
                            &mut |mut eh: MutableEthernetPacket| {
                                eh.clone_from(packet);
                            })
    }
}

struct DataLinkReceiverImpl {
    desc: Arc<NmDesc>,
    timeout: Option<libc::timespec>,
}

impl EthernetDataLinkReceiver for DataLinkReceiverImpl {
    // FIXME Layer 3
    fn iter<'a>(&'a mut self) -> Box<EthernetDataLinkChannelIterator + 'a> {
        Box::new(DataLinkChannelIteratorImpl { pc: self })
    }
}

struct DataLinkChannelIteratorImpl<'a> {
    pc: &'a mut DataLinkReceiverImpl,
}

impl<'a> EthernetDataLinkChannelIterator<'a> for DataLinkChannelIteratorImpl<'a> {
    fn next(&mut self) -> io::Result<EthernetPacket> {
        let desc = self.pc.desc.desc;
        let mut h: nm_pkthdr = unsafe { mem::uninitialized() };
        let mut buf = unsafe { nm_nextpkt(desc, &mut h) };
        if buf.is_null() {
            let mut fds = pollfd {
                fd: unsafe { NETMAP_FD(desc) },
                events: POLLIN,
                revents: 0,
            };
            let timespec = self.pc.timeout.as_ref().map(|ts| ts as *const _).unwrap_or(ptr::null());
            if unsafe { ppoll(&mut fds, 1, timespec, ptr::null()) } < 0 {
                return Err(io::Error::last_os_error());
            }
            buf = unsafe { nm_nextpkt(desc, &mut h) };
        }
        Ok(EthernetPacket::new(unsafe {
            slice::from_raw_parts(buf, h.len as usize)
        }).unwrap())
    }
}

/// Get a list of available network interfaces for the current machine.
pub fn interfaces() -> Vec<NetworkInterface> {
    #[path = "unix_interfaces.rs"]
    mod interfaces;
    interfaces::interfaces()
}
<|endoftext|>


<commit_before>use std;
use std::fmt;
use std::fmt::Write;
use core::Message;
use reflect::ReflectFieldRef;
use reflect::ProtobufValueRef;

fn quote_bytes_to(bytes: &[u8], buf: &mut String) {
    for &c in bytes {
        match c {
            b'\n' => buf.push_str(r"\n"),
            b'\r' => buf.push_str(r"\r"),
            b'\t' => buf.push_str(r"\t"),
            b'"' => buf.push_str("\\\""),
            b'\\' => buf.push_str(r"\\"),
            b'\x20'...b'\x7e' => buf.push(c as char),
            _ => {
                buf.push('\\');
                buf.push((b'0' + (c >> 6)) as char);
                buf.push((b'0' + ((c >> 3) & 7)) as char);
                buf.push((b'0' + (c & 7)) as char);
            }
        }
    }
}

fn quote_escape_bytes_to(bytes: &[u8], buf: &mut String) {
    buf.push('"');
    quote_bytes_to(bytes, buf);
    buf.push('"');
}

pub fn quote_escape_bytes(bytes: &[u8]) -> String {
    let mut r = String::new();
    quote_escape_bytes_to(bytes, &mut r);
    r
}

pub fn unescape_string(string: &str) -> Vec<u8> {
    fn parse_if_digit(chars: &mut std::str::Chars) -> u8 {
        let mut copy = chars.clone();
        let f = match copy.next() {
            None => return 0,
            Some(f) => f,
        };
        let d = match f {
            '0'...'9' => (f as u8 - b'0'),
            _ => return 0,
        };
        *chars = copy;
        d
    }

    fn parse_hex_digit(chars: &mut std::str::Chars) -> u8 {
        match chars.next().unwrap() {
            c @ '0'...'9' => (c as u8) - b'0',
            c @ 'a'...'f' => (c as u8) - b'a' + 10,
            c @ 'A'...'F' => (c as u8) - b'A' + 10,
            _ => panic!("incorrect hex escape"),
        }
    }

    fn parse_escape_rem(chars: &mut std::str::Chars) -> u8 {
        let n = chars.next().unwrap();
        match n {
            'a' => return b'\x07',
            'b' => return b'\x08',
            'f' => return b'\x0c',
            'n' => return b'\n',
            'r' => return b'\r',
            't' => return b'\t',
            'v' => return b'\x0b',
            '"' => return b'"',
            '\'' => return b'\'',
            '0'...'9' => {
                let d1 = n as u8 - b'0';
                let d2 = parse_if_digit(chars);
                let d3 = parse_if_digit(chars);
                return (d1 * 64 + d2 * 8 + d3) as u8;
            },
            'x' => {
                let d1 = parse_hex_digit(chars);
                let d2 = parse_hex_digit(chars);
                return d1 * 16 + d2;
            }
            c => return c as u8, // TODO: validate ASCII
        };
    }

    let mut chars = string.chars();
    let mut r = Vec::new();

    loop {
        let f = match chars.next() {
            None => return r,
            Some(f) => f,
        };

        if f == '\\' {
            r.push(parse_escape_rem(&mut chars));
        } else {
            r.push(f as u8); // TODO: escape UTF-8
        }
    }
}

fn print_str_to(s: &str, buf: &mut String) {
    // TODO: keep printable Unicode
    quote_escape_bytes_to(s.as_bytes(), buf);
}

fn do_indent(buf: &mut String, pretty: bool, indent: usize) {
    if pretty && indent > 0 {
        for _ in 0..indent {
            buf.push_str("  ");
        }
    }
}

fn print_start_field(
    buf: &mut String,
    pretty: bool,
    indent: usize,
    first: &mut bool,
    field_name: &str,
) {
    if !*first && !pretty {
        buf.push_str(" ");
    }
    do_indent(buf, pretty, indent);
    *first = false;
    buf.push_str(field_name);
}

fn print_end_field(buf: &mut String, pretty: bool) {
    if pretty {
        buf.push_str("\n");
    }
}

fn print_field(
    buf: &mut String,
    pretty: bool,
    indent: usize,
    first: &mut bool,
    field_name: &str,
    value: ProtobufValueRef,
) {
    print_start_field(buf, pretty, indent, first, field_name);

    match value {
        ProtobufValueRef::Message(m) => {
            buf.push_str(" {");
            if pretty {
                buf.push_str("\n");
            }
            print_to_internal(m, buf, pretty, indent + 1);
            do_indent(buf, pretty, indent);
            buf.push_str("}");
        }
        ProtobufValueRef::Enum(e) => {
            buf.push_str(": ");
            buf.push_str(e.name());
        }
        ProtobufValueRef::String(s) => {
            buf.push_str(": ");
            print_str_to(s, buf);
        }
        ProtobufValueRef::Bytes(b) => {
            buf.push_str(": ");
            quote_escape_bytes_to(b, buf);
        }
        ProtobufValueRef::I32(v) => {
            write!(buf, ": {}", v).unwrap();
        }
        ProtobufValueRef::I64(v) => {
            write!(buf, ": {}", v).unwrap();
        }
        ProtobufValueRef::U32(v) => {
            write!(buf, ": {}", v).unwrap();
        }
        ProtobufValueRef::U64(v) => {
            write!(buf, ": {}", v).unwrap();
        }
        ProtobufValueRef::Bool(v) => {
            write!(buf, ": {}", v).unwrap();
        }
        ProtobufValueRef::F32(v) => {
            write!(buf, ": {}", v).unwrap();
        }
        ProtobufValueRef::F64(v) => {
            write!(buf, ": {}", v).unwrap();
        }
    }

    print_end_field(buf, pretty);
}

fn print_to_internal(m: &Message, buf: &mut String, pretty: bool, indent: usize) {
    let d = m.descriptor();
    let mut first = true;
    for f in d.fields() {
        match f.get_reflect(m) {
            ReflectFieldRef::Map(map) => {
                for (k, v) in map {
                    print_start_field(buf, pretty, indent, &mut first, f.name());
                    buf.push_str(" {");
                    if pretty {
                        buf.push_str("\n");
                    }

                    let mut entry_first = true;

                    print_field(buf, pretty, indent + 1, &mut entry_first, "key", k.as_ref());
                    print_field(
                        buf,
                        pretty,
                        indent + 1,
                        &mut entry_first,
                        "value",
                        v.as_ref(),
                    );
                    do_indent(buf, pretty, indent);
                    buf.push_str("}");
                    print_end_field(buf, pretty);
                }
            }
            ReflectFieldRef::Repeated(repeated) => {
                // TODO: do not print zeros for v3
                for v in repeated {
                    print_field(buf, pretty, indent, &mut first, f.name(), v.as_ref());
                }
            }
            ReflectFieldRef::Optional(optional) => {
                if let Some(v) = optional {
                    print_field(buf, pretty, indent, &mut first, f.name(), v);
                }
            }
        }
    }

    // TODO: unknown fields
}

pub fn print_to(m: &Message, buf: &mut String) {
    print_to_internal(m, buf, false, 0)
}

fn print_to_string_internal(m: &Message, pretty: bool) -> String {
    let mut r = String::new();
    print_to_internal(m, &mut r, pretty, 0);
    r.to_string()
}

pub fn print_to_string(m: &Message) -> String {
    print_to_string_internal(m, false)
}

pub fn fmt(m: &Message, f: &mut fmt::Formatter) -> fmt::Result {
    let pretty = f.alternate();
    f.write_str(&print_to_string_internal(m, pretty))
}

#[cfg(test)]
mod test {

    fn escape(data: &[u8]) -> String {
        let mut s = String::with_capacity(data.len() * 4);
        super::quote_bytes_to(data, &mut s);
        s
    }

    fn test_escape_unescape(text: &str, escaped: &str) {
        assert_eq!(text.as_bytes(), &super::unescape_string(escaped)[..]);
        assert_eq!(escaped, &escape(text.as_bytes())[..]);
    }

    #[test]
    fn test_print_to_bytes() {
        assert_eq!("ab", escape(b"ab"));
        assert_eq!("a\\\\023", escape(b"a\\023"));
        assert_eq!("a\\r\\n\\t '\\\"\\\\", escape(b"a\r\n\t '\"\\"));
        assert_eq!(
            "\\344\\275\\240\\345\\245\\275",
            escape("你好".as_bytes())
        );
    }

    #[test]
    fn test_unescape_string() {
        test_escape_unescape("", "");
        test_escape_unescape("aa", "aa");
        test_escape_unescape("\n", "\\n");
        test_escape_unescape("\r", "\\r");
        test_escape_unescape("\t", "\\t");
        test_escape_unescape("你好", "\\344\\275\\240\\345\\245\\275");
        // hex
        assert_eq!(b"aaa\x01bbb", &super::unescape_string("aaa\\x01bbb")[..]);
        assert_eq!(b"aaa\xcdbbb", &super::unescape_string("aaa\\xCDbbb")[..]);
        assert_eq!(b"aaa\xcdbbb", &super::unescape_string("aaa\\xCDbbb")[..]);
        // quotes
        assert_eq!(b"aaa\"bbb", &super::unescape_string("aaa\\\"bbb")[..]);
        assert_eq!(b"aaa\'bbb", &super::unescape_string("aaa\\\'bbb")[..]);
    }
}
<commit_msg>Hide functions which are not a public API<commit_after>use std;
use std::fmt;
use std::fmt::Write;
use core::Message;
use reflect::ReflectFieldRef;
use reflect::ProtobufValueRef;

fn quote_bytes_to(bytes: &[u8], buf: &mut String) {
    for &c in bytes {
        match c {
            b'\n' => buf.push_str(r"\n"),
            b'\r' => buf.push_str(r"\r"),
            b'\t' => buf.push_str(r"\t"),
            b'"' => buf.push_str("\\\""),
            b'\\' => buf.push_str(r"\\"),
            b'\x20'...b'\x7e' => buf.push(c as char),
            _ => {
                buf.push('\\');
                buf.push((b'0' + (c >> 6)) as char);
                buf.push((b'0' + ((c >> 3) & 7)) as char);
                buf.push((b'0' + (c & 7)) as char);
            }
        }
    }
}

fn quote_escape_bytes_to(bytes: &[u8], buf: &mut String) {
    buf.push('"');
    quote_bytes_to(bytes, buf);
    buf.push('"');
}

#[doc(hidden)]
pub fn quote_escape_bytes(bytes: &[u8]) -> String {
    let mut r = String::new();
    quote_escape_bytes_to(bytes, &mut r);
    r
}

#[doc(hidden)]
pub fn unescape_string(string: &str) -> Vec<u8> {
    fn parse_if_digit(chars: &mut std::str::Chars) -> u8 {
        let mut copy = chars.clone();
        let f = match copy.next() {
            None => return 0,
            Some(f) => f,
        };
        let d = match f {
            '0'...'9' => (f as u8 - b'0'),
            _ => return 0,
        };
        *chars = copy;
        d
    }

    fn parse_hex_digit(chars: &mut std::str::Chars) -> u8 {
        match chars.next().unwrap() {
            c @ '0'...'9' => (c as u8) - b'0',
            c @ 'a'...'f' => (c as u8) - b'a' + 10,
            c @ 'A'...'F' => (c as u8) - b'A' + 10,
            _ => panic!("incorrect hex escape"),
        }
    }

    fn parse_escape_rem(chars: &mut std::str::Chars) -> u8 {
        let n = chars.next().unwrap();
        match n {
            'a' => return b'\x07',
            'b' => return b'\x08',
            'f' => return b'\x0c',
            'n' => return b'\n',
            'r' => return b'\r',
            't' => return b'\t',
            'v' => return b'\x0b',
            '"' => return b'"',
            '\'' => return b'\'',
            '0'...'9' => {
                let d1 = n as u8 - b'0';
                let d2 = parse_if_digit(chars);
                let d3 = parse_if_digit(chars);
                return (d1 * 64 + d2 * 8 + d3) as u8;
            },
            'x' => {
                let d1 = parse_hex_digit(chars);
                let d2 = parse_hex_digit(chars);
                return d1 * 16 + d2;
            }
            c => return c as u8, // TODO: validate ASCII
        };
    }

    let mut chars = string.chars();
    let mut r = Vec::new();

    loop {
        let f = match chars.next() {
            None => return r,
            Some(f) => f,
        };

        if f == '\\' {
            r.push(parse_escape_rem(&mut chars));
        } else {
            r.push(f as u8); // TODO: escape UTF-8
        }
    }
}

fn print_str_to(s: &str, buf: &mut String) {
    // TODO: keep printable Unicode
    quote_escape_bytes_to(s.as_bytes(), buf);
}

fn do_indent(buf: &mut String, pretty: bool, indent: usize) {
    if pretty && indent > 0 {
        for _ in 0..indent {
            buf.push_str("  ");
        }
    }
}

fn print_start_field(
    buf: &mut String,
    pretty: bool,
    indent: usize,
    first: &mut bool,
    field_name: &str,
) {
    if !*first && !pretty {
        buf.push_str(" ");
    }
    do_indent(buf, pretty, indent);
    *first = false;
    buf.push_str(field_name);
}

fn print_end_field(buf: &mut String, pretty: bool) {
    if pretty {
        buf.push_str("\n");
    }
}

fn print_field(
    buf: &mut String,
    pretty: bool,
    indent: usize,
    first: &mut bool,
    field_name: &str,
    value: ProtobufValueRef,
) {
    print_start_field(buf, pretty, indent, first, field_name);

    match value {
        ProtobufValueRef::Message(m) => {
            buf.push_str(" {");
            if pretty {
                buf.push_str("\n");
            }
            print_to_internal(m, buf, pretty, indent + 1);
            do_indent(buf, pretty, indent);
            buf.push_str("}");
        }
        ProtobufValueRef::Enum(e) => {
            buf.push_str(": ");
            buf.push_str(e.name());
        }
        ProtobufValueRef::String(s) => {
            buf.push_str(": ");
            print_str_to(s, buf);
        }
        ProtobufValueRef::Bytes(b) => {
            buf.push_str(": ");
            quote_escape_bytes_to(b, buf);
        }
        ProtobufValueRef::I32(v) => {
            write!(buf, ": {}", v).unwrap();
        }
        ProtobufValueRef::I64(v) => {
            write!(buf, ": {}", v).unwrap();
        }
        ProtobufValueRef::U32(v) => {
            write!(buf, ": {}", v).unwrap();
        }
        ProtobufValueRef::U64(v) => {
            write!(buf, ": {}", v).unwrap();
        }
        ProtobufValueRef::Bool(v) => {
            write!(buf, ": {}", v).unwrap();
        }
        ProtobufValueRef::F32(v) => {
            write!(buf, ": {}", v).unwrap();
        }
        ProtobufValueRef::F64(v) => {
            write!(buf, ": {}", v).unwrap();
        }
    }

    print_end_field(buf, pretty);
}

fn print_to_internal(m: &Message, buf: &mut String, pretty: bool, indent: usize) {
    let d = m.descriptor();
    let mut first = true;
    for f in d.fields() {
        match f.get_reflect(m) {
            ReflectFieldRef::Map(map) => {
                for (k, v) in map {
                    print_start_field(buf, pretty, indent, &mut first, f.name());
                    buf.push_str(" {");
                    if pretty {
                        buf.push_str("\n");
                    }

                    let mut entry_first = true;

                    print_field(buf, pretty, indent + 1, &mut entry_first, "key", k.as_ref());
                    print_field(
                        buf,
                        pretty,
                        indent + 1,
                        &mut entry_first,
                        "value",
                        v.as_ref(),
                    );
                    do_indent(buf, pretty, indent);
                    buf.push_str("}");
                    print_end_field(buf, pretty);
                }
            }
            ReflectFieldRef::Repeated(repeated) => {
                // TODO: do not print zeros for v3
                for v in repeated {
                    print_field(buf, pretty, indent, &mut first, f.name(), v.as_ref());
                }
            }
            ReflectFieldRef::Optional(optional) => {
                if let Some(v) = optional {
                    print_field(buf, pretty, indent, &mut first, f.name(), v);
                }
            }
        }
    }

    // TODO: unknown fields
}

pub fn print_to(m: &Message, buf: &mut String) {
    print_to_internal(m, buf, false, 0)
}

fn print_to_string_internal(m: &Message, pretty: bool) -> String {
    let mut r = String::new();
    print_to_internal(m, &mut r, pretty, 0);
    r.to_string()
}

pub fn print_to_string(m: &Message) -> String {
    print_to_string_internal(m, false)
}

pub fn fmt(m: &Message, f: &mut fmt::Formatter) -> fmt::Result {
    let pretty = f.alternate();
    f.write_str(&print_to_string_internal(m, pretty))
}

#[cfg(test)]
mod test {

    fn escape(data: &[u8]) -> String {
        let mut s = String::with_capacity(data.len() * 4);
        super::quote_bytes_to(data, &mut s);
        s
    }

    fn test_escape_unescape(text: &str, escaped: &str) {
        assert_eq!(text.as_bytes(), &super::unescape_string(escaped)[..]);
        assert_eq!(escaped, &escape(text.as_bytes())[..]);
    }

    #[test]
    fn test_print_to_bytes() {
        assert_eq!("ab", escape(b"ab"));
        assert_eq!("a\\\\023", escape(b"a\\023"));
        assert_eq!("a\\r\\n\\t '\\\"\\\\", escape(b"a\r\n\t '\"\\"));
        assert_eq!(
            "\\344\\275\\240\\345\\245\\275",
            escape("你好".as_bytes())
        );
    }

    #[test]
    fn test_unescape_string() {
        test_escape_unescape("", "");
        test_escape_unescape("aa", "aa");
        test_escape_unescape("\n", "\\n");
        test_escape_unescape("\r", "\\r");
        test_escape_unescape("\t", "\\t");
        test_escape_unescape("你好", "\\344\\275\\240\\345\\245\\275");
        // hex
        assert_eq!(b"aaa\x01bbb", &super::unescape_string("aaa\\x01bbb")[..]);
        assert_eq!(b"aaa\xcdbbb", &super::unescape_string("aaa\\xCDbbb")[..]);
        assert_eq!(b"aaa\xcdbbb", &super::unescape_string("aaa\\xCDbbb")[..]);
        // quotes
        assert_eq!(b"aaa\"bbb", &super::unescape_string("aaa\\\"bbb")[..]);
        assert_eq!(b"aaa\'bbb", &super::unescape_string("aaa\\\'bbb")[..]);
    }
}
<|endoftext|>


<commit_before>#![no_std]
#![feature(no_std)]
#![feature(core, core_prelude, core_slice_ext, slice_bytes)]

#[macro_use]
extern crate core;

use core::prelude::*;
use core::cmp::min;
use core::slice::bytes::copy_memory;

#[macro_export]
macro_rules! try {
	($expr:expr) => (match $expr {
		::core::result::Result::Ok(val) => val,
		::core::result::Result::Err(err) => {
			return ::core::result::Result::Err(::core::convert::From::from(err))
		}
	})
}

#[derive(Copy, Clone, Debug)]
pub struct EndOfFile;

#[derive(Copy, Clone, Debug)]
pub struct OutOfBounds;

pub trait Read {
	type Err;

	fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Err>;

	fn read_all<E=<Self as Read>::Err>(&mut self, buf: &mut [u8]) -> Result<(), E> where E: From<Self::Err> + From<EndOfFile> {
		let mut offset = 0;
		while offset < buf.len() {
			match try!(self.read(&mut buf[offset..])) {
				0 => return Err(E::from(EndOfFile)),
				n => offset += n
			}
		}
		Ok(())
	}
}

pub trait Write {
	type Err;

	fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Err>;

	fn write_all<E=<Self as Write>::Err>(&mut self, mut buf: &[u8]) -> Result<(), E> where E: From<Self::Err> + From<EndOfFile> {
		while buf.len() > 0 {
			match try!(self.write(buf)) {
				0 => return Err(E::from(EndOfFile)),
				n => buf = &buf[n..]
			}
		}
		Ok(())
	}
}

pub enum SeekFrom {
	Start(u64),
	End(i64),
	Current(i64),
}

pub trait Seek {
	type Err;

	fn seek(&mut self, pos: SeekFrom) -> Result<u64, Self::Err>;

	fn tell(&mut self) -> Result<u64, Self::Err> {
		self.seek(SeekFrom::Current(0))
	}
}

impl<'a> Read for &'a [u8] {
	type Err = EndOfFile;

	fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Err> {
		let len = min(buf.len(), self.len());
		if len == 0 {
			return Err(EndOfFile)
		}
		let (a, b) = self.split_at(len);
		copy_memory(a, buf);
		*self = b;
		Ok(len)
	}
}

pub struct Cursor<T> {
	inner: T,
	pos: u64
}

impl<T> Cursor<T> {
	pub fn new(inner: T) -> Cursor<T> {
		Cursor {
			inner: inner,
			pos: 0
		}
	}
}

impl<'a> Read for Cursor<&'a [u8]> {
	type Err = EndOfFile;

	fn read(&mut self, buf: &mut [u8]) -> Result<usize, EndOfFile> {
		let len = try!((&self.inner[self.pos as usize..]).read(buf));
		self.pos += len as u64;
		Ok(len)
	}
}

impl<'a> Seek for Cursor<&'a [u8]> {
	type Err = OutOfBounds;

	fn seek(&mut self, from: SeekFrom) -> Result<u64, OutOfBounds> {
		let pos = match from {
			SeekFrom::Start(offset) => offset as i64,
			SeekFrom::End(offset) => self.inner.len() as i64 + offset as i64,
			SeekFrom::Current(offset) => self.pos as i64 + offset
		};
		if pos < 0 {
			return Err(OutOfBounds);
		}
		self.pos = min(pos as u64, self.inner.len() as u64);
		Ok(self.pos)
	}
}

impl<'a, R: Read> Read for &'a mut R {
	type Err = R::Err;

	fn read(&mut self, buf: &mut [u8]) -> Result<usize, R::Err> {
		(**self).read(buf)
	}

	fn read_all<E=<Self as Read>::Err>(&mut self, buf: &mut [u8]) -> Result<(), E> where E: From<R::Err> + From<EndOfFile> {
		(**self).read_all(buf)
	}
}

impl<'a, W: Write> Write for &'a mut W {
	type Err = W::Err;

	fn write(&mut self, buf: &[u8]) -> Result<usize, W::Err> {
		(**self).write(buf)
	}

	fn write_all<E=<Self as Write>::Err>(&mut self, buf: &[u8]) -> Result<(), E> where E: From<W::Err> + From<EndOfFile> {
		(**self).write_all(buf)
	}
}

impl<'a, S: Seek> Seek for &'a mut S {
	type Err = S::Err;

	fn seek(&mut self, pos: SeekFrom) -> Result<u64, S::Err> {
		(**self).seek(pos)
	}

	fn tell(&mut self) -> Result<u64, S::Err> {
		(**self).tell()
	}
}
<commit_msg>Rustup<commit_after>#![no_std]
#![feature(no_std)]
#![feature(core_slice_ext, slice_bytes)]

use core::cmp::min;
use core::slice::bytes::copy_memory;

#[macro_export]
macro_rules! try {
	($expr:expr) => (match $expr {
		::core::result::Result::Ok(val) => val,
		::core::result::Result::Err(err) => {
			return ::core::result::Result::Err(::core::convert::From::from(err))
		}
	})
}

#[derive(Copy, Clone, Debug)]
pub struct EndOfFile;

#[derive(Copy, Clone, Debug)]
pub struct OutOfBounds;

pub trait Read {
	type Err;

	fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Err>;

	fn read_all<E=<Self as Read>::Err>(&mut self, buf: &mut [u8]) -> Result<(), E> where E: From<Self::Err> + From<EndOfFile> {
		let mut offset = 0;
		while offset < buf.len() {
			match try!(self.read(&mut buf[offset..])) {
				0 => return Err(E::from(EndOfFile)),
				n => offset += n
			}
		}
		Ok(())
	}
}

pub trait Write {
	type Err;

	fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Err>;

	fn write_all<E=<Self as Write>::Err>(&mut self, mut buf: &[u8]) -> Result<(), E> where E: From<Self::Err> + From<EndOfFile> {
		while buf.len() > 0 {
			match try!(self.write(buf)) {
				0 => return Err(E::from(EndOfFile)),
				n => buf = &buf[n..]
			}
		}
		Ok(())
	}
}

pub enum SeekFrom {
	Start(u64),
	End(i64),
	Current(i64),
}

pub trait Seek {
	type Err;

	fn seek(&mut self, pos: SeekFrom) -> Result<u64, Self::Err>;

	fn tell(&mut self) -> Result<u64, Self::Err> {
		self.seek(SeekFrom::Current(0))
	}
}

impl<'a> Read for &'a [u8] {
	type Err = EndOfFile;

	fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Err> {
		let len = min(buf.len(), self.len());
		if len == 0 {
			return Err(EndOfFile)
		}
		let (a, b) = self.split_at(len);
		copy_memory(a, buf);
		*self = b;
		Ok(len)
	}
}

pub struct Cursor<T> {
	inner: T,
	pos: u64
}

impl<T> Cursor<T> {
	pub fn new(inner: T) -> Cursor<T> {
		Cursor {
			inner: inner,
			pos: 0
		}
	}
}

impl<'a> Read for Cursor<&'a [u8]> {
	type Err = EndOfFile;

	fn read(&mut self, buf: &mut [u8]) -> Result<usize, EndOfFile> {
		let len = try!((&self.inner[self.pos as usize..]).read(buf));
		self.pos += len as u64;
		Ok(len)
	}
}

impl<'a> Seek for Cursor<&'a [u8]> {
	type Err = OutOfBounds;

	fn seek(&mut self, from: SeekFrom) -> Result<u64, OutOfBounds> {
		let pos = match from {
			SeekFrom::Start(offset) => offset as i64,
			SeekFrom::End(offset) => self.inner.len() as i64 + offset as i64,
			SeekFrom::Current(offset) => self.pos as i64 + offset
		};
		if pos < 0 {
			return Err(OutOfBounds);
		}
		self.pos = min(pos as u64, self.inner.len() as u64);
		Ok(self.pos)
	}
}

impl<'a, R: Read> Read for &'a mut R {
	type Err = R::Err;

	fn read(&mut self, buf: &mut [u8]) -> Result<usize, R::Err> {
		(**self).read(buf)
	}

	fn read_all<E=<Self as Read>::Err>(&mut self, buf: &mut [u8]) -> Result<(), E> where E: From<R::Err> + From<EndOfFile> {
		(**self).read_all(buf)
	}
}

impl<'a, W: Write> Write for &'a mut W {
	type Err = W::Err;

	fn write(&mut self, buf: &[u8]) -> Result<usize, W::Err> {
		(**self).write(buf)
	}

	fn write_all<E=<Self as Write>::Err>(&mut self, buf: &[u8]) -> Result<(), E> where E: From<W::Err> + From<EndOfFile> {
		(**self).write_all(buf)
	}
}

impl<'a, S: Seek> Seek for &'a mut S {
	type Err = S::Err;

	fn seek(&mut self, pos: SeekFrom) -> Result<u64, S::Err> {
		(**self).seek(pos)
	}

	fn tell(&mut self) -> Result<u64, S::Err> {
		(**self).tell()
	}
}
<|endoftext|>