<commit_before>use std::str::FromStr;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6, SocketAddr};
use std::path::PathBuf;
use std::fmt::Debug;

use http::uri::{URI, Segments, SegmentError};

/// Trait to convert a dynamic path segment string to a concrete value.
///
/// This trait is used by Rocket's code generation facilities to parse dynamic
/// path segment string values into a given type. That is, when a path contains
/// a dynamic segment `<param>` where `param` has some type `T` that implements
/// `FromParam`, `T::from_param` will be called.
///
/// # Forwarding
///
/// If the conversion fails, the incoming request will be forwarded to the next
/// matching route, if any. For instance, consider the following route and
/// handler for the dynamic `"/<id>"` path:
///
/// ```rust
/// # #![feature(plugin)]
/// # #![plugin(rocket_codegen)]
/// # extern crate rocket;
/// #[get("/<id>")]
/// fn hello(id: usize) -> String {
/// # let _id = id;
/// # /*
///     ...
/// # */
/// # "".to_string()
/// }
/// # fn main() {  }
/// ```
///
/// If `usize::from_param` returns an `Ok(usize)` variant, the encapsulated
/// value is used as the `id` function parameter. If not, the request is
/// forwarded to the next matching route. Since there are no additional matching
/// routes, this example will result in a 404 error for requests with invalid
/// `id` values.
///
/// # Catching Errors
///
/// Sometimes, a forward is not desired, and instead, we simply want to know
/// that the dynamic path segment could not be parsed into some desired type
/// `T`. In these cases, types of `Option<T>` or `Result<T, T::Error>` can be
/// used. These types implement `FromParam` themselves. Their implementations
/// always return successfully, so they never forward. They can be used to
/// determine if the `FromParam` call failed and to retrieve the error value
/// from the failed `from_param` call.
///
/// For instance, imagine you've asked for an `<id>` as a `usize`. To determine
/// when the `<id>` was not a valid `usize` and retrieve the string that failed
/// to parse, you can use a `Result<usize, &str>` type for the `<id>` parameter
/// as follows:
///
/// ```rust
/// # #![feature(plugin)]
/// # #![plugin(rocket_codegen)]
/// # extern crate rocket;
/// #[get("/<id>")]
/// fn hello(id: Result<usize, &str>) -> String {
///     match id {
///         Ok(id_num) => format!("usize: {}", id_num),
///         Err(string) => format!("Not a usize: {}", string)
///     }
/// }
/// # fn main() {  }
/// ```
///
/// # Provided Implementations
///
/// Rocket implements `FromParam` for several standard library types. Their
/// behavior is documented here.
///
///   * **f32, f64, isize, i8, i16, i32, i64, usize, u8, u16, u32, u64, bool
///     IpAddr, Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6, SocketAddr**
///
///     A value is parse successfully if the `from_str` method from the given
///     type returns successfully. Otherwise, the raw path segment is returned
///     in the `Err` value.
///
///   * **str**
///
///     _This implementation always returns successfully._
///
///     The path segment is passed directly with no modification.
///
///   * **String**
///
///     Percent decodes the path segment. If the decode is successful, the
///     decoded string is returned. Otherwise, an `Err` with the original path
///     segment is returned.
///
///   * **Option<T>** _where_ **T: FromParam**
///
///     _This implementation always returns successfully._
///
///     The path segment is parsed by `T`'s `FromParam` implementation. If the
///     parse succeeds, a `Some(parsed_value)` is returned. Otherwise, a `None`
///     is returned.
///
///   * **Result<T, T::Error>** _where_ **T: FromParam**
///
///     _This implementation always returns successfully._
///
///     The path segment is parsed by `T`'s `FromParam` implementation. The
///     returned `Result` value is returned.
///
/// # `str` vs. `String`
///
/// Paths are URL encoded. As a result, the `str` `FromParam` implementation
/// returns the raw, URL encoded version of the path segment string. On the
/// other hand, `String` decodes the path parameter, but requires an allocation
/// to do so. This tradeoff is similiar to that of form values, and you should
/// use whichever makes sense for your application.
///
/// # Example
///
/// Say you want to parse a segment of the form:
///
/// ```ignore
/// [a-zA-Z]+:[0-9]+
/// ```
///
/// into the following structure, where the string before the `:` is stored in
/// `key` and the number after the colon is stored in `value`:
///
/// ```rust
/// # #[allow(dead_code)]
/// struct MyParam<'r> {
///     key: &'r str,
///     value: usize
/// }
/// ```
///
/// The following implementation accomplishes this:
///
/// ```rust
/// use rocket::request::FromParam;
/// # #[allow(dead_code)]
/// # struct MyParam<'r> { key: &'r str, value: usize }
///
/// impl<'r> FromParam<'r> for MyParam<'r> {
///     type Error = &'r str;
///
///     fn from_param(param: &'r str) -> Result<MyParam<'r>, &'r str> {
///         let (key, val_str) = match param.find(':') {
///             Some(i) if i > 0 => (&param[..i], &param[(i + 1)..]),
///             _ => return Err(param)
///         };
///
///         if !key.chars().all(|c| (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
///             return Err(param);
///         }
///
///         val_str.parse().map(|value| {
///             MyParam {
///                 key: key,
///                 value: value
///             }
///         }).map_err(|_| param)
///     }
/// }
/// ```
///
/// With the implementation, the `MyParam` type can be used as the target of a
/// dynamic path segment:
///
/// ```rust
/// # #![feature(plugin)]
/// # #![plugin(rocket_codegen)]
/// # extern crate rocket;
/// # use rocket::request::FromParam;
/// # #[allow(dead_code)]
/// # struct MyParam<'r> { key: &'r str, value: usize }
/// # impl<'r> FromParam<'r> for MyParam<'r> {
/// #     type Error = &'r str;
/// #     fn from_param(param: &'r str) -> Result<MyParam<'r>, &'r str> {
/// #         Err(param)
/// #     }
/// # }
/// #
/// #[get("/<key_val>")]
/// fn hello(key_val: MyParam) -> String {
/// # let _kv = key_val;
/// # /*
///     ...
/// # */
/// # "".to_string()
/// }
/// # fn main() {  }
/// ```
pub trait FromParam<'a>: Sized {
    /// The associated error to be returned when parsing fails.
    type Error: Debug;

    /// Parses an instance of `Self` from a dynamic path parameter string or
    /// returns an `Error` if one cannot be parsed.
    fn from_param(param: &'a str) -> Result<Self, Self::Error>;
}

impl<'a> FromParam<'a> for &'a str {
    type Error = ();
    fn from_param(param: &'a str) -> Result<&'a str, Self::Error> {
        Ok(param)
    }
}

impl<'a> FromParam<'a> for String {
    type Error = &'a str;
    fn from_param(p: &'a str) -> Result<String, Self::Error> {
        URI::percent_decode(p.as_bytes()).map_err(|_| p).map(|s| s.into_owned())
    }
}

macro_rules! impl_with_fromstr {
    ($($T:ident),+) => ($(
        impl<'a> FromParam<'a> for $T {
            type Error = &'a str;
            fn from_param(param: &'a str) -> Result<Self, Self::Error> {
                $T::from_str(param).map_err(|_| param)
            }
        }
    )+)
}

impl_with_fromstr!(f32, f64, isize, i8, i16, i32, i64, usize, u8, u16, u32, u64,
       bool, IpAddr, Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6,
       SocketAddr);

impl<'a, T: FromParam<'a>> FromParam<'a> for Result<T, T::Error> {
    type Error = ();
    fn from_param(p: &'a str) -> Result<Self, Self::Error> {
        Ok(match T::from_param(p) {
            Ok(val) => Ok(val),
            Err(e) => Err(e),
        })
    }
}

impl<'a, T: FromParam<'a>> FromParam<'a> for Option<T> {
    type Error = ();
    fn from_param(p: &'a str) -> Result<Self, Self::Error> {
        Ok(match T::from_param(p) {
            Ok(val) => Some(val),
            Err(_) => None
        })
    }
}

/// Trait to convert _many_ dynamic path segment strings to a concrete value.
///
/// This is the `..` analog to [FromParam](trait.FromParam.html), and its
/// functionality is identical to it with one exception: this trait applies to
/// segment parameters of the form `<param..>`, where `param` is of some type
/// `T` that implements `FromSegments`. `T::from_segments` is called to convert
/// the matched segments (via the
/// [Segments](/rocket/http/uri/struct.Segments.html) iterator) into the
/// implementing type.
///
/// # Provided Implementations
///
/// Rocket implements `FromParam` for `PathBuf`. The `PathBuf` implementation
/// constructs a path from the segments iterator. Each segment is
/// percent-decoded. If a segment equals ".." before or after decoding, the
/// previous segment (if any) is omitted. For security purposes, any other
/// segments that begin with "*" or "." are ignored.  If a percent-decoded
/// segment results in invalid UTF8, an `Err` is returned with the `Utf8Error`.
pub trait FromSegments<'a>: Sized {
    /// The associated error to be returned when parsing fails.
    type Error: Debug;

    /// Parses an instance of `Self` from many dynamic path parameter strings or
    /// returns an `Error` if one cannot be parsed.
    fn from_segments(segments: Segments<'a>) -> Result<Self, Self::Error>;
}

impl<'a> FromSegments<'a> for Segments<'a> {
    type Error = ();

    fn from_segments(segments: Segments<'a>) -> Result<Segments<'a>, ()> {
        Ok(segments)
    }
}

/// Creates a `PathBuf` from a `Segments` iterator. The returned `PathBuf` is
/// percent-decoded. If a segment is equal to "..", the previous segment (if
/// any) is skipped.
///
/// For security purposes, if a segment meets any of the following conditions,
/// an `Err` is returned indicating the condition met:
///
///   * Decoded segment starts with any of: `.`, `*`
///   * Decoded segment ends with any of: `:`, `>`, `<`
///   * Decoded segment contains any of: `/`
///   * On Windows, decoded segment contains any of: '\'
///   * Percent-encoding results in invalid UTF8.
///
/// As a result of these conditions, a `PathBuf` derived via `FromSegments` is
/// safe to interpolate within, or use as a suffix of, a path without additional
/// checks.
impl<'a> FromSegments<'a> for PathBuf {
    type Error = SegmentError;

    fn from_segments(segments: Segments<'a>) -> Result<PathBuf, SegmentError> {
        let mut buf = PathBuf::new();
        for segment in segments {
            let decoded = URI::percent_decode(segment.as_bytes())
                .map_err(|e| SegmentError::Utf8(e))?;

            if decoded == ".." {
                buf.pop();
            } else if decoded.starts_with('.') {
                return Err(SegmentError::BadStart('.'))
            } else if decoded.starts_with('*') {
                return Err(SegmentError::BadStart('*'))
            } else if decoded.ends_with(':') {
                return Err(SegmentError::BadEnd(':'))
            } else if decoded.ends_with('>') {
                return Err(SegmentError::BadEnd('>'))
            } else if decoded.ends_with('<') {
                return Err(SegmentError::BadEnd('<'))
            } else if decoded.contains('/') {
                return Err(SegmentError::BadChar('/'))
            } else if cfg!(windows) && decoded.contains('\\') {
                return Err(SegmentError::BadChar('\\'))
            } else {
                buf.push(&*decoded)
            }
        }

        Ok(buf)
    }
}

impl<'a, T: FromSegments<'a>> FromSegments<'a> for Result<T, T::Error> {
    type Error = ();
    fn from_segments(segments: Segments<'a>) -> Result<Result<T, T::Error>, ()> {
        Ok(match T::from_segments(segments) {
            Ok(val) => Ok(val),
            Err(e) => Err(e),
        })
    }
}

impl<'a, T: FromSegments<'a>> FromSegments<'a> for Option<T> {
    type Error = ();
    fn from_segments(segments: Segments<'a>) -> Result<Option<T>, ()> {
        Ok(match T::from_segments(segments) {
            Ok(val) => Some(val),
            Err(_) => None
        })
    }
}
<commit_msg>Small typo: parse -> parsed.<commit_after>use std::str::FromStr;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6, SocketAddr};
use std::path::PathBuf;
use std::fmt::Debug;

use http::uri::{URI, Segments, SegmentError};

/// Trait to convert a dynamic path segment string to a concrete value.
///
/// This trait is used by Rocket's code generation facilities to parse dynamic
/// path segment string values into a given type. That is, when a path contains
/// a dynamic segment `<param>` where `param` has some type `T` that implements
/// `FromParam`, `T::from_param` will be called.
///
/// # Forwarding
///
/// If the conversion fails, the incoming request will be forwarded to the next
/// matching route, if any. For instance, consider the following route and
/// handler for the dynamic `"/<id>"` path:
///
/// ```rust
/// # #![feature(plugin)]
/// # #![plugin(rocket_codegen)]
/// # extern crate rocket;
/// #[get("/<id>")]
/// fn hello(id: usize) -> String {
/// # let _id = id;
/// # /*
///     ...
/// # */
/// # "".to_string()
/// }
/// # fn main() {  }
/// ```
///
/// If `usize::from_param` returns an `Ok(usize)` variant, the encapsulated
/// value is used as the `id` function parameter. If not, the request is
/// forwarded to the next matching route. Since there are no additional matching
/// routes, this example will result in a 404 error for requests with invalid
/// `id` values.
///
/// # Catching Errors
///
/// Sometimes, a forward is not desired, and instead, we simply want to know
/// that the dynamic path segment could not be parsed into some desired type
/// `T`. In these cases, types of `Option<T>` or `Result<T, T::Error>` can be
/// used. These types implement `FromParam` themselves. Their implementations
/// always return successfully, so they never forward. They can be used to
/// determine if the `FromParam` call failed and to retrieve the error value
/// from the failed `from_param` call.
///
/// For instance, imagine you've asked for an `<id>` as a `usize`. To determine
/// when the `<id>` was not a valid `usize` and retrieve the string that failed
/// to parse, you can use a `Result<usize, &str>` type for the `<id>` parameter
/// as follows:
///
/// ```rust
/// # #![feature(plugin)]
/// # #![plugin(rocket_codegen)]
/// # extern crate rocket;
/// #[get("/<id>")]
/// fn hello(id: Result<usize, &str>) -> String {
///     match id {
///         Ok(id_num) => format!("usize: {}", id_num),
///         Err(string) => format!("Not a usize: {}", string)
///     }
/// }
/// # fn main() {  }
/// ```
///
/// # Provided Implementations
///
/// Rocket implements `FromParam` for several standard library types. Their
/// behavior is documented here.
///
///   * **f32, f64, isize, i8, i16, i32, i64, usize, u8, u16, u32, u64, bool
///     IpAddr, Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6, SocketAddr**
///
///     A value is parsed successfully if the `from_str` method from the given
///     type returns successfully. Otherwise, the raw path segment is returned
///     in the `Err` value.
///
///   * **str**
///
///     _This implementation always returns successfully._
///
///     The path segment is passed directly with no modification.
///
///   * **String**
///
///     Percent decodes the path segment. If the decode is successful, the
///     decoded string is returned. Otherwise, an `Err` with the original path
///     segment is returned.
///
///   * **Option<T>** _where_ **T: FromParam**
///
///     _This implementation always returns successfully._
///
///     The path segment is parsed by `T`'s `FromParam` implementation. If the
///     parse succeeds, a `Some(parsed_value)` is returned. Otherwise, a `None`
///     is returned.
///
///   * **Result<T, T::Error>** _where_ **T: FromParam**
///
///     _This implementation always returns successfully._
///
///     The path segment is parsed by `T`'s `FromParam` implementation. The
///     returned `Result` value is returned.
///
/// # `str` vs. `String`
///
/// Paths are URL encoded. As a result, the `str` `FromParam` implementation
/// returns the raw, URL encoded version of the path segment string. On the
/// other hand, `String` decodes the path parameter, but requires an allocation
/// to do so. This tradeoff is similiar to that of form values, and you should
/// use whichever makes sense for your application.
///
/// # Example
///
/// Say you want to parse a segment of the form:
///
/// ```ignore
/// [a-zA-Z]+:[0-9]+
/// ```
///
/// into the following structure, where the string before the `:` is stored in
/// `key` and the number after the colon is stored in `value`:
///
/// ```rust
/// # #[allow(dead_code)]
/// struct MyParam<'r> {
///     key: &'r str,
///     value: usize
/// }
/// ```
///
/// The following implementation accomplishes this:
///
/// ```rust
/// use rocket::request::FromParam;
/// # #[allow(dead_code)]
/// # struct MyParam<'r> { key: &'r str, value: usize }
///
/// impl<'r> FromParam<'r> for MyParam<'r> {
///     type Error = &'r str;
///
///     fn from_param(param: &'r str) -> Result<MyParam<'r>, &'r str> {
///         let (key, val_str) = match param.find(':') {
///             Some(i) if i > 0 => (&param[..i], &param[(i + 1)..]),
///             _ => return Err(param)
///         };
///
///         if !key.chars().all(|c| (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
///             return Err(param);
///         }
///
///         val_str.parse().map(|value| {
///             MyParam {
///                 key: key,
///                 value: value
///             }
///         }).map_err(|_| param)
///     }
/// }
/// ```
///
/// With the implementation, the `MyParam` type can be used as the target of a
/// dynamic path segment:
///
/// ```rust
/// # #![feature(plugin)]
/// # #![plugin(rocket_codegen)]
/// # extern crate rocket;
/// # use rocket::request::FromParam;
/// # #[allow(dead_code)]
/// # struct MyParam<'r> { key: &'r str, value: usize }
/// # impl<'r> FromParam<'r> for MyParam<'r> {
/// #     type Error = &'r str;
/// #     fn from_param(param: &'r str) -> Result<MyParam<'r>, &'r str> {
/// #         Err(param)
/// #     }
/// # }
/// #
/// #[get("/<key_val>")]
/// fn hello(key_val: MyParam) -> String {
/// # let _kv = key_val;
/// # /*
///     ...
/// # */
/// # "".to_string()
/// }
/// # fn main() {  }
/// ```
pub trait FromParam<'a>: Sized {
    /// The associated error to be returned when parsing fails.
    type Error: Debug;

    /// Parses an instance of `Self` from a dynamic path parameter string or
    /// returns an `Error` if one cannot be parsed.
    fn from_param(param: &'a str) -> Result<Self, Self::Error>;
}

impl<'a> FromParam<'a> for &'a str {
    type Error = ();
    fn from_param(param: &'a str) -> Result<&'a str, Self::Error> {
        Ok(param)
    }
}

impl<'a> FromParam<'a> for String {
    type Error = &'a str;
    fn from_param(p: &'a str) -> Result<String, Self::Error> {
        URI::percent_decode(p.as_bytes()).map_err(|_| p).map(|s| s.into_owned())
    }
}

macro_rules! impl_with_fromstr {
    ($($T:ident),+) => ($(
        impl<'a> FromParam<'a> for $T {
            type Error = &'a str;
            fn from_param(param: &'a str) -> Result<Self, Self::Error> {
                $T::from_str(param).map_err(|_| param)
            }
        }
    )+)
}

impl_with_fromstr!(f32, f64, isize, i8, i16, i32, i64, usize, u8, u16, u32, u64,
       bool, IpAddr, Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6,
       SocketAddr);

impl<'a, T: FromParam<'a>> FromParam<'a> for Result<T, T::Error> {
    type Error = ();
    fn from_param(p: &'a str) -> Result<Self, Self::Error> {
        Ok(match T::from_param(p) {
            Ok(val) => Ok(val),
            Err(e) => Err(e),
        })
    }
}

impl<'a, T: FromParam<'a>> FromParam<'a> for Option<T> {
    type Error = ();
    fn from_param(p: &'a str) -> Result<Self, Self::Error> {
        Ok(match T::from_param(p) {
            Ok(val) => Some(val),
            Err(_) => None
        })
    }
}

/// Trait to convert _many_ dynamic path segment strings to a concrete value.
///
/// This is the `..` analog to [FromParam](trait.FromParam.html), and its
/// functionality is identical to it with one exception: this trait applies to
/// segment parameters of the form `<param..>`, where `param` is of some type
/// `T` that implements `FromSegments`. `T::from_segments` is called to convert
/// the matched segments (via the
/// [Segments](/rocket/http/uri/struct.Segments.html) iterator) into the
/// implementing type.
///
/// # Provided Implementations
///
/// Rocket implements `FromParam` for `PathBuf`. The `PathBuf` implementation
/// constructs a path from the segments iterator. Each segment is
/// percent-decoded. If a segment equals ".." before or after decoding, the
/// previous segment (if any) is omitted. For security purposes, any other
/// segments that begin with "*" or "." are ignored.  If a percent-decoded
/// segment results in invalid UTF8, an `Err` is returned with the `Utf8Error`.
pub trait FromSegments<'a>: Sized {
    /// The associated error to be returned when parsing fails.
    type Error: Debug;

    /// Parses an instance of `Self` from many dynamic path parameter strings or
    /// returns an `Error` if one cannot be parsed.
    fn from_segments(segments: Segments<'a>) -> Result<Self, Self::Error>;
}

impl<'a> FromSegments<'a> for Segments<'a> {
    type Error = ();

    fn from_segments(segments: Segments<'a>) -> Result<Segments<'a>, ()> {
        Ok(segments)
    }
}

/// Creates a `PathBuf` from a `Segments` iterator. The returned `PathBuf` is
/// percent-decoded. If a segment is equal to "..", the previous segment (if
/// any) is skipped.
///
/// For security purposes, if a segment meets any of the following conditions,
/// an `Err` is returned indicating the condition met:
///
///   * Decoded segment starts with any of: `.`, `*`
///   * Decoded segment ends with any of: `:`, `>`, `<`
///   * Decoded segment contains any of: `/`
///   * On Windows, decoded segment contains any of: '\'
///   * Percent-encoding results in invalid UTF8.
///
/// As a result of these conditions, a `PathBuf` derived via `FromSegments` is
/// safe to interpolate within, or use as a suffix of, a path without additional
/// checks.
impl<'a> FromSegments<'a> for PathBuf {
    type Error = SegmentError;

    fn from_segments(segments: Segments<'a>) -> Result<PathBuf, SegmentError> {
        let mut buf = PathBuf::new();
        for segment in segments {
            let decoded = URI::percent_decode(segment.as_bytes())
                .map_err(|e| SegmentError::Utf8(e))?;

            if decoded == ".." {
                buf.pop();
            } else if decoded.starts_with('.') {
                return Err(SegmentError::BadStart('.'))
            } else if decoded.starts_with('*') {
                return Err(SegmentError::BadStart('*'))
            } else if decoded.ends_with(':') {
                return Err(SegmentError::BadEnd(':'))
            } else if decoded.ends_with('>') {
                return Err(SegmentError::BadEnd('>'))
            } else if decoded.ends_with('<') {
                return Err(SegmentError::BadEnd('<'))
            } else if decoded.contains('/') {
                return Err(SegmentError::BadChar('/'))
            } else if cfg!(windows) && decoded.contains('\\') {
                return Err(SegmentError::BadChar('\\'))
            } else {
                buf.push(&*decoded)
            }
        }

        Ok(buf)
    }
}

impl<'a, T: FromSegments<'a>> FromSegments<'a> for Result<T, T::Error> {
    type Error = ();
    fn from_segments(segments: Segments<'a>) -> Result<Result<T, T::Error>, ()> {
        Ok(match T::from_segments(segments) {
            Ok(val) => Ok(val),
            Err(e) => Err(e),
        })
    }
}

impl<'a, T: FromSegments<'a>> FromSegments<'a> for Option<T> {
    type Error = ();
    fn from_segments(segments: Segments<'a>) -> Result<Option<T>, ()> {
        Ok(match T::from_segments(segments) {
            Ok(val) => Some(val),
            Err(_) => None
        })
    }
}
<|endoftext|>


<commit_before>//use serde::ser::{Serialize, Serializer, SerializeStruct};
//use serde::de::{Deserialize, Deserializer, Visitor, Error as DeError, MapAccess};
//use std::fmt;
//
//const AMI_LAUNCH_INDEX: &'static str = "ami-launch-index";
//const LOCAL_HOSTNAME: &'static str = "local-hostname";
//const AVAILABILITY_ZONE: &'static str = "availability-zone";
//const INSTANCE_ID: &'static str = "instance-id";
//const PUBLIC_IPV4: &'static str = "public-ipv4";
//const PUBLIC_HOSTNAME: &'static str = "public-hostname";
//const AMI_MANIFEST_PATH: &'static str = "ami-manifest-path";
//const LOCAL_IPV4: &'static str = "local-ipv4";
//const HOSTNAME: &'static str = "hostname";
//const AMI_ID: &'static str = "ami-id";
//const INSTANCE_TYPE: &'static str = "instance-type";
//const JSON_FIELDS: &'static [&'static str] = &[AMI_LAUNCH_INDEX, LOCAL_HOSTNAME, AVAILABILITY_ZONE, INSTANCE_ID,
//    PUBLIC_IPV4, PUBLIC_HOSTNAME, AMI_MANIFEST_PATH, LOCAL_IPV4,
//    HOSTNAME, AMI_ID, INSTANCE_TYPE];
//const RUST_FIELDS: &'static [&'static str] = &["ami_launch_index", "local_hostname", "availability_zone", "instance_id",
//    "public_ip4", "public_hostname", "ami_manifest_path", "local_ip4", "hostname", "ami_id", "instance_type"];
//const AMAZON_META_DATA: &'static str = "AmazonMetaData";

#[derive(Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub struct AmazonMetaData {
    pub ami_launch_index: String,
    pub local_hostname: String,
    pub availability_zone: String,
    pub instance_id: String,
    pub public_ipv4: String,
    pub public_hostname: String,
    pub ami_manifest_path: String,
    pub local_ipv4: String,
    pub hostname: String,
    pub ami_id: String,
    pub instance_type: String
}

//impl Serialize for AmazonMetaData {
//    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where
//        S: Serializer {
//        let mut s = serializer.serialize_struct(AMAZON_META_DATA, 11)?;
//        s.serialize_field(AMI_LAUNCH_INDEX, &self.ami_launch_index)?;
//        s.serialize_field(LOCAL_HOSTNAME, &self.local_hostname)?;
//        s.serialize_field(AVAILABILITY_ZONE, &self.availability_zone)?;
//        s.serialize_field(INSTANCE_ID, &self.instance_id)?;
//        s.serialize_field(PUBLIC_IPV4, &self.public_ip4)?;
//        s.serialize_field(PUBLIC_HOSTNAME, &self.public_hostname)?;
//        s.serialize_field(AMI_MANIFEST_PATH, &self.ami_manifest_path)?;
//        s.serialize_field(LOCAL_IPV4, &self.local_ip4)?;
//        s.serialize_field(HOSTNAME, &self.hostname)?;
//        s.serialize_field(AMI_ID, &self.ami_id)?;
//        s.serialize_field(INSTANCE_TYPE, &self.instance_type)?;
//        s.end()
//    }
//}

//impl<'de> Deserialize<'de> for AmazonMetaData {
//    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where
//        D: Deserializer<'de> {
//        enum Field { AmiLaunchIndex, LocalHostname, AvailabilityZone, InstanceId, PublicIp4, PublicHostname, AmiManifestPath, LocalIp4, Hostname, AmiId, InstanceType };
//
//        impl<'de> Deserialize<'de> for Field {
//            fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where
//                D: Deserializer<'de> {
//                struct FieldVisitor;
//
//                impl<'de> Visitor<'de> for FieldVisitor {
//                    type Value = Field;
//
//                    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
//                        formatter.write_str("An AmazonMetaData field (see schema)")
//                    }
//
//                    fn visit_str<E>(self, v: &str) -> Result<Self::Value, E> where
//                        E: DeError {
//                        match v {
//                            AMI_LAUNCH_INDEX => Ok(Field::AmiLaunchIndex),
//                            LOCAL_HOSTNAME => Ok(Field::LocalHostname),
//                            AVAILABILITY_ZONE => Ok(Field::AvailabilityZone),
//                            INSTANCE_ID => Ok(Field::InstanceId),
//                            PUBLIC_IPV4 => Ok(Field::PublicIp4),
//                            PUBLIC_HOSTNAME => Ok(Field::PublicHostname),
//                            AMI_MANIFEST_PATH => Ok(Field::AmiManifestPath),
//                            LOCAL_IPV4 => Ok(Field::LocalIp4),
//                            HOSTNAME => Ok(Field::Hostname),
//                            AMI_ID => Ok(Field::AmiId),
//                            INSTANCE_TYPE => Ok(Field::InstanceType),
//                            _ => Err(DeError::unknown_field(v, JSON_FIELDS))
//                        }
//                    }
//                }
//
//                deserializer.deserialize_identifier(FieldVisitor)
//            }
//        }
//
//        struct AmazonMetaDataVisitor;
//
//        impl<'de> Visitor<'de> for AmazonMetaDataVisitor {
//            type Value = AmazonMetaData;
//
//            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
//                formatter.write_str("struct AmazonMetaDataVisitor")
//            }
//
//            fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error> where
//                A: MapAccess<'de> {
//                let mut maybe_ami_launch_index = None;
//                let mut maybe_local_hostname = None;
//                let mut maybe_availability_zone = None;
//                let mut maybe_instance_id = None;
//                let mut maybe_public_ip4 = None;
//                let mut maybe_public_hostname = None;
//                let mut maybe_ami_manifest_path = None;
//                let mut maybe_local_ip4 = None;
//                let mut maybe_hostname = None;
//                let mut maybe_ami_id = None;
//                let mut maybe_instance_type = None;
//
//                while let Some(key) = map.next_key()? {
//                    match key {
//                        Field::AmiLaunchIndex => {
//                            if maybe_ami_launch_index.is_some() {
//                                return Err(DeError::duplicate_field(AMI_LAUNCH_INDEX));
//                            }
//                            maybe_ami_launch_index = Some(map.next_value()?)
//                        },
//                        Field::LocalHostname => {
//                            if maybe_local_hostname.is_some() {
//                                return Err(DeError::duplicate_field(LOCAL_HOSTNAME));
//                            }
//                            maybe_local_hostname = Some(map.next_value()?)
//                        },
//                        Field::AvailabilityZone => {
//                            if maybe_availability_zone.is_some() {
//                                return Err(DeError::duplicate_field(AVAILABILITY_ZONE));
//                            }
//                            maybe_availability_zone= Some(map.next_value()?)
//                        },
//                        Field::InstanceId => {
//                            if maybe_instance_id.is_some() {
//                                return Err(DeError::duplicate_field(INSTANCE_ID));
//                            }
//                            maybe_instance_id= Some(map.next_value()?)
//                        },
//                        Field::PublicIp4 => {
//                            if maybe_public_ip4.is_some() {
//                                return Err(DeError::duplicate_field(PUBLIC_IPV4));
//                            }
//                            maybe_public_ip4= Some(map.next_value()?)
//                        },
//                        Field::PublicHostname => {
//                            if maybe_public_hostname.is_some() {
//                                return Err(DeError::duplicate_field(PUBLIC_HOSTNAME));
//                            }
//                            maybe_public_hostname= Some(map.next_value()?)
//                        },
//                        Field::AmiManifestPath => {
//                            if maybe_ami_manifest_path.is_some() {
//                                return Err(DeError::duplicate_field(AMI_MANIFEST_PATH));
//                            }
//                            maybe_ami_manifest_path= Some(map.next_value()?)
//                        },
//                        Field::LocalIp4 => {
//                            if maybe_local_ip4.is_some() {
//                                return Err(DeError::duplicate_field(LOCAL_IPV4));
//                            }
//                            maybe_local_ip4= Some(map.next_value()?)
//                        },
//                        Field::Hostname => {
//                            if maybe_hostname.is_some() {
//                                return Err(DeError::duplicate_field(HOSTNAME));
//                            }
//                            maybe_hostname= Some(map.next_value()?)
//                        },
//                        Field::AmiId => {
//                            if maybe_ami_id.is_some() {
//                                return Err(DeError::duplicate_field(AMI_ID));
//                            }
//                            maybe_ami_id= Some(map.next_value()?)
//                        },
//                        Field::InstanceType => {
//                            if maybe_instance_type.is_some() {
//                                return Err(DeError::duplicate_field(INSTANCE_TYPE));
//                            }
//                            maybe_instance_type= Some(map.next_value()?)
//                        }
//                    }
//                }
//
//                let ami_launch_index = maybe_ami_launch_index.ok_or_else(|| DeError::missing_field(AMI_LAUNCH_INDEX));
//                let local_hostname = maybe_local_hostname.ok_or_else(|| DeError::missing_field(LOCAL_HOSTNAME));
//                let availability_zone = maybe_availability_zone.ok_or_else(|| DeError::missing_field(AVAILABILITY_ZONE));
//                let instance_id = maybe_instance_id.ok_or_else(|| DeError::missing_field(INSTANCE_ID));
//                let public_ip4 = maybe_public_ip4.ok_or_else(|| DeError::missing_field(PUBLIC_IPV4));
//                let public_hostname = maybe_public_hostname.ok_or_else(|| DeError::missing_field(PUBLIC_HOSTNAME));
//                let ami_manifest_path = maybe_ami_manifest_path.ok_or_else(|| DeError::missing_field(AMI_MANIFEST_PATH));
//                let local_ip4 = maybe_local_ip4.ok_or_else(|| DeError::missing_field(LOCAL_IPV4));
//                let hostname = maybe_hostname.ok_or_else(|| DeError::missing_field(HOSTNAME));
//                let ami_id = maybe_ami_id.ok_or_else(|| DeError::missing_field(AMI_ID));
//                let instance_type = maybe_instance_type.ok_or_else(|| DeError::missing_field(INSTANCE_TYPE));
//
//                Ok(AmazonMetaData {
//                    ami_launch_index: ami_launch_index?,
//                    local_hostname: local_hostname?,
//                    availability_zone: availability_zone?,
//                    instance_id: instance_id?,
//                    public_ip4: public_ip4?,
//                    public_hostname: public_hostname?,
//                    ami_manifest_path: ami_manifest_path?,
//                    local_ip4: local_ip4?,
//                    hostname: hostname?,
//                    ami_id: ami_id?,
//                    instance_type: instance_type?
//                })
//            }
//        }
//        deserializer.deserialize_struct(AMAZON_META_DATA, RUST_FIELDS, AmazonMetaDataVisitor)
//    }
//}

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

    #[test]
    fn test_serialize_amazon_meta_data() {
        let md = AmazonMetaData {
            ami_launch_index: "001a".to_string(),
            local_hostname: "localhost0".to_string(),
            availability_zone: "US_East1a".to_string(),
            instance_id: "instance1a".to_string(),
            public_ipv4: "32.23.21.212".to_string(),
            public_hostname: "foo.coma".to_string(),
            ami_manifest_path: "/dev/nulla".to_string(),
            local_ipv4: "127.0.0.12".to_string(),
            hostname: "privatefoo.coma".to_string(),
            ami_id: "ami0023".to_string(),
            instance_type: "c4xlarged".to_string()
        };
        let json = sample_meta_data();

        let result = serde_json::to_string(&md).unwrap();
        assert_eq!(json, result);
    }

    #[test]
    fn test_deserialize_amazon_meta_data() {
        let md = AmazonMetaData {
            ami_launch_index: "001a".to_string(),
            local_hostname: "localhost0".to_string(),
            availability_zone: "US_East1a".to_string(),
            instance_id: "instance1a".to_string(),
            public_ipv4: "32.23.21.212".to_string(),
            public_hostname: "foo.coma".to_string(),
            ami_manifest_path: "/dev/nulla".to_string(),
            local_ipv4: "127.0.0.12".to_string(),
            hostname: "privatefoo.coma".to_string(),
            ami_id: "ami0023".to_string(),
            instance_type: "c4xlarged".to_string()
        };
        let json = sample_meta_data();
        let result = serde_json::from_str(&json).unwrap();
        assert_eq!(md, result);
    }

    pub fn sample_meta_data() -> String {
        r#"{ "ami-launch-index": "001a",
            "local-hostname": "localhost0",
            "availability-zone": "US_East1a",
            "instance-id": "instance1a",
            "public-ipv4": "32.23.21.212",
            "public-hostname": "foo.coma",
            "ami-manifest-path": "/dev/nulla",
            "local-ipv4": "127.0.0.12",
            "hostname": "privatefoo.coma",
            "ami-id": "ami0023",
            "instance-type": "c4xlarged" }"#
            .to_string()
            .replace(" ", "")
            .replace("\n", "")
    }
}<commit_msg>Removed old commented code from when wrote the json serialization/deserialization by hand.<commit_after>#[derive(Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub struct AmazonMetaData {
    pub ami_launch_index: String,
    pub local_hostname: String,
    pub availability_zone: String,
    pub instance_id: String,
    pub public_ipv4: String,
    pub public_hostname: String,
    pub ami_manifest_path: String,
    pub local_ipv4: String,
    pub hostname: String,
    pub ami_id: String,
    pub instance_type: String
}

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

    #[test]
    fn test_serialize_amazon_meta_data() {
        let md = AmazonMetaData {
            ami_launch_index: "001a".to_string(),
            local_hostname: "localhost0".to_string(),
            availability_zone: "US_East1a".to_string(),
            instance_id: "instance1a".to_string(),
            public_ipv4: "32.23.21.212".to_string(),
            public_hostname: "foo.coma".to_string(),
            ami_manifest_path: "/dev/nulla".to_string(),
            local_ipv4: "127.0.0.12".to_string(),
            hostname: "privatefoo.coma".to_string(),
            ami_id: "ami0023".to_string(),
            instance_type: "c4xlarged".to_string()
        };
        let json = sample_meta_data();

        let result = serde_json::to_string(&md).unwrap();
        assert_eq!(json, result);
    }

    #[test]
    fn test_deserialize_amazon_meta_data() {
        let md = AmazonMetaData {
            ami_launch_index: "001a".to_string(),
            local_hostname: "localhost0".to_string(),
            availability_zone: "US_East1a".to_string(),
            instance_id: "instance1a".to_string(),
            public_ipv4: "32.23.21.212".to_string(),
            public_hostname: "foo.coma".to_string(),
            ami_manifest_path: "/dev/nulla".to_string(),
            local_ipv4: "127.0.0.12".to_string(),
            hostname: "privatefoo.coma".to_string(),
            ami_id: "ami0023".to_string(),
            instance_type: "c4xlarged".to_string()
        };
        let json = sample_meta_data();
        let result = serde_json::from_str(&json).unwrap();
        assert_eq!(md, result);
    }

    pub fn sample_meta_data() -> String {
        r#"{ "ami-launch-index": "001a",
            "local-hostname": "localhost0",
            "availability-zone": "US_East1a",
            "instance-id": "instance1a",
            "public-ipv4": "32.23.21.212",
            "public-hostname": "foo.coma",
            "ami-manifest-path": "/dev/nulla",
            "local-ipv4": "127.0.0.12",
            "hostname": "privatefoo.coma",
            "ami-id": "ami0023",
            "instance-type": "c4xlarged" }"#
            .to_string()
            .replace(" ", "")
            .replace("\n", "")
    }
}<|endoftext|>


<commit_before>use std::io::mem::MemReader;
use std::io::File;

mod toml;

fn main() {
  let contents = File::open(&Path::new(std::os::args()[1])).read_to_end();
  let mut rd = MemReader::new(contents);

  let mut builder = toml::ValueBuilder::new();
  let mut parser = toml::Parser::new(&mut rd);
  parser.parse(&mut builder);
  println!("{:s}", builder.get_root().to_str());
}
<commit_msg>Use BufferedReader<commit_after>use std::io::mem::MemReader;
use std::io::buffered::BufferedReader;
use std::io::File;

mod toml;

fn main() {
  let path = Path::new(std::os::args()[1]);
  let mut file = File::open(&path);

  //let contents = file.read_to_end();
  //let mut rd = MemReader::new(contents);
  let mut rd = BufferedReader::new(file);

  let mut builder = toml::ValueBuilder::new();
  let mut parser = toml::Parser::new(&mut rd);
  parser.parse(&mut builder);
  println!("{:s}", builder.get_root().to_str());
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate askama;

use askama::Template;

use std::collections::HashMap;

#[derive(Template)]
#[template(path = "simple.html")]
struct VariablesTemplate<'a> {
    strvar: &'a str,
    num: i64,
    i18n: String,
}

#[test]
fn test_variables() {
    let s = VariablesTemplate {
        strvar: "foo",
        num: 42,
        i18n: "Iñtërnâtiônàlizætiøn".to_string(),
    };
    assert_eq!(
        s.render().unwrap(),
        "\nhello world, foo\n\
         with number: 42\n\
         Iñtërnâtiônàlizætiøn is important\n\
         in vars too: Iñtërnâtiônàlizætiøn"
    );
}

#[derive(Template)]
#[template(path = "if.html")]
struct IfTemplate {
    cond: bool,
}

#[test]
fn test_if() {
    let s = IfTemplate { cond: true };
    assert_eq!(s.render().unwrap(), "true");
}

#[derive(Template)]
#[template(path = "else.html")]
struct ElseTemplate {
    cond: bool,
}

#[test]
fn test_else() {
    let s = ElseTemplate { cond: false };
    assert_eq!(s.render().unwrap(), "false");
}

#[derive(Template)]
#[template(path = "else-if.html")]
struct ElseIfTemplate {
    cond: bool,
    check: bool,
}

#[test]
fn test_else_if() {
    let s = ElseIfTemplate {
        cond: false,
        check: true,
    };
    assert_eq!(s.render().unwrap(), "checked");
}

#[derive(Template)]
#[template(path = "literals.html")]
struct LiteralsTemplate {}

#[test]
fn test_literals() {
    let s = LiteralsTemplate {};
    assert_eq!(s.render().unwrap(), "a");
}

struct Holder {
    a: usize,
}

#[derive(Template)]
#[template(path = "attr.html")]
struct AttrTemplate {
    inner: Holder,
}

#[test]
fn test_attr() {
    let t = AttrTemplate {
        inner: Holder { a: 5 },
    };
    assert_eq!(t.render().unwrap(), "5");
}

#[derive(Template)]
#[template(path = "tuple-attr.html")]
struct TupleAttrTemplate<'a> {
    tuple: (&'a str, &'a str),
}

#[test]
fn test_tuple_attr() {
    let t = TupleAttrTemplate {
        tuple: ("foo", "bar"),
    };
    assert_eq!(t.render().unwrap(), "foobar");
}

struct NestedHolder {
    holder: Holder,
}

#[derive(Template)]
#[template(path = "nested-attr.html")]
struct NestedAttrTemplate {
    inner: NestedHolder,
}

#[test]
fn test_nested_attr() {
    let t = NestedAttrTemplate {
        inner: NestedHolder {
            holder: Holder { a: 5 },
        },
    };
    assert_eq!(t.render().unwrap(), "5");
}

#[derive(Template)]
#[template(path = "option.html")]
struct OptionTemplate<'a> {
    var: Option<&'a str>,
}

#[test]
fn test_option() {
    let some = OptionTemplate { var: Some("foo") };
    assert_eq!(some.render().unwrap(), "some: foo");
    let none = OptionTemplate { var: None };
    assert_eq!(none.render().unwrap(), "none");
}

#[derive(Template)]
#[template(path = "generics.html")]
struct GenericsTemplate<T: std::fmt::Display, U = u8>
where
    U: std::fmt::Display,
{
    t: T,
    u: U,
}

#[test]
fn test_generics() {
    let t = GenericsTemplate { t: "a", u: 42 };
    assert_eq!(t.render().unwrap(), "a42");
}

#[derive(Template)]
#[template(path = "composition.html")]
struct CompositionTemplate {
    foo: IfTemplate,
}

#[test]
fn test_composition() {
    let t = CompositionTemplate {
        foo: IfTemplate { cond: true },
    };
    assert_eq!(t.render().unwrap(), "composed: true");
}

#[derive(PartialEq, Eq)]
enum Alphabet {
    Alpha,
}

#[derive(Template)]
#[template(source = "{% if x == Alphabet::Alpha %}true{% endif %}", ext = "txt")]
struct PathCompareTemplate {
    x: Alphabet,
}

#[test]
fn test_path_compare() {
    let t = PathCompareTemplate { x: Alphabet::Alpha };
    assert_eq!(t.render().unwrap(), "true");
}

#[derive(Template)]
#[template(source = "{% for i in [\"a\", \"\"] %}{{ i }}{% endfor %}", ext = "txt")]
struct ArrayTemplate {}

#[test]
fn test_slice_literal() {
    let t = ArrayTemplate {};
    assert_eq!(t.render().unwrap(), "a");
}

#[derive(Template)]
#[template(source = "  {# foo -#} ", ext = "txt")]
struct CommentTemplate {}

#[test]
fn test_comment() {
    let t = CommentTemplate {};
    assert_eq!(t.render().unwrap(), "  ");
}

#[derive(Template)]
#[template(source = "{% if !foo %}Hello{% endif %}", ext = "txt")]
struct NegationTemplate {
    foo: bool,
}

#[test]
fn test_negation() {
    let t = NegationTemplate { foo: false };
    assert_eq!(t.render().unwrap(), "Hello");
}

#[derive(Template)]
#[template(source = "{% if foo > -2 %}Hello{% endif %}", ext = "txt")]
struct MinusTemplate {
    foo: i8,
}

#[test]
fn test_minus() {
    let t = MinusTemplate { foo: 1 };
    assert_eq!(t.render().unwrap(), "Hello");
}

#[derive(Template)]
#[template(source = "{{ foo[\"bar\"] }}", ext = "txt", print = "code")]
struct IndexTemplate {
    foo: HashMap<String, String>,
}

#[test]
fn test_index() {
    let mut foo = HashMap::new();
    foo.insert("bar".into(), "baz".into());
    let t = IndexTemplate { foo };
    assert_eq!(t.render().unwrap(), "baz");
}
<commit_msg>Remove accidental debugging cruft<commit_after>#[macro_use]
extern crate askama;

use askama::Template;

use std::collections::HashMap;

#[derive(Template)]
#[template(path = "simple.html")]
struct VariablesTemplate<'a> {
    strvar: &'a str,
    num: i64,
    i18n: String,
}

#[test]
fn test_variables() {
    let s = VariablesTemplate {
        strvar: "foo",
        num: 42,
        i18n: "Iñtërnâtiônàlizætiøn".to_string(),
    };
    assert_eq!(
        s.render().unwrap(),
        "\nhello world, foo\n\
         with number: 42\n\
         Iñtërnâtiônàlizætiøn is important\n\
         in vars too: Iñtërnâtiônàlizætiøn"
    );
}

#[derive(Template)]
#[template(path = "if.html")]
struct IfTemplate {
    cond: bool,
}

#[test]
fn test_if() {
    let s = IfTemplate { cond: true };
    assert_eq!(s.render().unwrap(), "true");
}

#[derive(Template)]
#[template(path = "else.html")]
struct ElseTemplate {
    cond: bool,
}

#[test]
fn test_else() {
    let s = ElseTemplate { cond: false };
    assert_eq!(s.render().unwrap(), "false");
}

#[derive(Template)]
#[template(path = "else-if.html")]
struct ElseIfTemplate {
    cond: bool,
    check: bool,
}

#[test]
fn test_else_if() {
    let s = ElseIfTemplate {
        cond: false,
        check: true,
    };
    assert_eq!(s.render().unwrap(), "checked");
}

#[derive(Template)]
#[template(path = "literals.html")]
struct LiteralsTemplate {}

#[test]
fn test_literals() {
    let s = LiteralsTemplate {};
    assert_eq!(s.render().unwrap(), "a");
}

struct Holder {
    a: usize,
}

#[derive(Template)]
#[template(path = "attr.html")]
struct AttrTemplate {
    inner: Holder,
}

#[test]
fn test_attr() {
    let t = AttrTemplate {
        inner: Holder { a: 5 },
    };
    assert_eq!(t.render().unwrap(), "5");
}

#[derive(Template)]
#[template(path = "tuple-attr.html")]
struct TupleAttrTemplate<'a> {
    tuple: (&'a str, &'a str),
}

#[test]
fn test_tuple_attr() {
    let t = TupleAttrTemplate {
        tuple: ("foo", "bar"),
    };
    assert_eq!(t.render().unwrap(), "foobar");
}

struct NestedHolder {
    holder: Holder,
}

#[derive(Template)]
#[template(path = "nested-attr.html")]
struct NestedAttrTemplate {
    inner: NestedHolder,
}

#[test]
fn test_nested_attr() {
    let t = NestedAttrTemplate {
        inner: NestedHolder {
            holder: Holder { a: 5 },
        },
    };
    assert_eq!(t.render().unwrap(), "5");
}

#[derive(Template)]
#[template(path = "option.html")]
struct OptionTemplate<'a> {
    var: Option<&'a str>,
}

#[test]
fn test_option() {
    let some = OptionTemplate { var: Some("foo") };
    assert_eq!(some.render().unwrap(), "some: foo");
    let none = OptionTemplate { var: None };
    assert_eq!(none.render().unwrap(), "none");
}

#[derive(Template)]
#[template(path = "generics.html")]
struct GenericsTemplate<T: std::fmt::Display, U = u8>
where
    U: std::fmt::Display,
{
    t: T,
    u: U,
}

#[test]
fn test_generics() {
    let t = GenericsTemplate { t: "a", u: 42 };
    assert_eq!(t.render().unwrap(), "a42");
}

#[derive(Template)]
#[template(path = "composition.html")]
struct CompositionTemplate {
    foo: IfTemplate,
}

#[test]
fn test_composition() {
    let t = CompositionTemplate {
        foo: IfTemplate { cond: true },
    };
    assert_eq!(t.render().unwrap(), "composed: true");
}

#[derive(PartialEq, Eq)]
enum Alphabet {
    Alpha,
}

#[derive(Template)]
#[template(source = "{% if x == Alphabet::Alpha %}true{% endif %}", ext = "txt")]
struct PathCompareTemplate {
    x: Alphabet,
}

#[test]
fn test_path_compare() {
    let t = PathCompareTemplate { x: Alphabet::Alpha };
    assert_eq!(t.render().unwrap(), "true");
}

#[derive(Template)]
#[template(source = "{% for i in [\"a\", \"\"] %}{{ i }}{% endfor %}", ext = "txt")]
struct ArrayTemplate {}

#[test]
fn test_slice_literal() {
    let t = ArrayTemplate {};
    assert_eq!(t.render().unwrap(), "a");
}

#[derive(Template)]
#[template(source = "  {# foo -#} ", ext = "txt")]
struct CommentTemplate {}

#[test]
fn test_comment() {
    let t = CommentTemplate {};
    assert_eq!(t.render().unwrap(), "  ");
}

#[derive(Template)]
#[template(source = "{% if !foo %}Hello{% endif %}", ext = "txt")]
struct NegationTemplate {
    foo: bool,
}

#[test]
fn test_negation() {
    let t = NegationTemplate { foo: false };
    assert_eq!(t.render().unwrap(), "Hello");
}

#[derive(Template)]
#[template(source = "{% if foo > -2 %}Hello{% endif %}", ext = "txt")]
struct MinusTemplate {
    foo: i8,
}

#[test]
fn test_minus() {
    let t = MinusTemplate { foo: 1 };
    assert_eq!(t.render().unwrap(), "Hello");
}

#[derive(Template)]
#[template(source = "{{ foo[\"bar\"] }}", ext = "txt")]
struct IndexTemplate {
    foo: HashMap<String, String>,
}

#[test]
fn test_index() {
    let mut foo = HashMap::new();
    foo.insert("bar".into(), "baz".into());
    let t = IndexTemplate { foo };
    assert_eq!(t.render().unwrap(), "baz");
}
<|endoftext|>


<commit_before>//! Memory allocation APIs
//!
//! In a given program, the standard library has one “global” memory allocator
//! that is used for example by `Box<T>` and `Vec<T>`.
//!
//! Currently the default global allocator is unspecified. Libraries, however,
//! like `cdylib`s and `staticlib`s are guaranteed to use the [`System`] by
//! default.
//!
//! [`System`]: struct.System.html
//!
//! # The `#[global_allocator]` attribute
//!
//! This attribute allows configuring the choice of global allocator.
//! You can use this to implement a completely custom global allocator
//! to route all default allocation requests to a custom object.
//!
//! ```rust
//! use std::alloc::{GlobalAlloc, System, Layout};
//!
//! struct MyAllocator;
//!
//! unsafe impl GlobalAlloc for MyAllocator {
//!     unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
//!         System.alloc(layout)
//!     }
//!
//!     unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
//!         System.dealloc(ptr, layout)
//!     }
//! }
//!
//! #[global_allocator]
//! static GLOBAL: MyAllocator = MyAllocator;
//!
//! fn main() {
//!     // This `Vec` will allocate memory through `GLOBAL` above
//!     let mut v = Vec::new();
//!     v.push(1);
//! }
//! ```
//!
//! The attribute is used on a `static` item whose type implements the
//! [`GlobalAlloc`] trait. This type can be provided by an external library:
//!
//! [`GlobalAlloc`]: ../../core/alloc/trait.GlobalAlloc.html
//!
//! ```rust,ignore (demonstrates crates.io usage)
//! extern crate jemallocator;
//!
//! use jemallocator::Jemalloc;
//!
//! #[global_allocator]
//! static GLOBAL: Jemalloc = Jemalloc;
//!
//! fn main() {}
//! ```
//!
//! The `#[global_allocator]` can only be used once in a crate
//! or its recursive dependencies.

#![deny(unsafe_op_in_unsafe_fn)]
#![stable(feature = "alloc_module", since = "1.28.0")]

use core::intrinsics;
use core::ptr::NonNull;
use core::sync::atomic::{AtomicPtr, Ordering};
use core::{mem, ptr};

use crate::sys_common::util::dumb_print;

#[stable(feature = "alloc_module", since = "1.28.0")]
#[doc(inline)]
pub use alloc_crate::alloc::*;

/// The default memory allocator provided by the operating system.
///
/// This is based on `malloc` on Unix platforms and `HeapAlloc` on Windows,
/// plus related functions.
///
/// This type implements the `GlobalAlloc` trait and Rust programs by default
/// work as if they had this definition:
///
/// ```rust
/// use std::alloc::System;
///
/// #[global_allocator]
/// static A: System = System;
///
/// fn main() {
///     let a = Box::new(4); // Allocates from the system allocator.
///     println!("{}", a);
/// }
/// ```
///
/// You can also define your own wrapper around `System` if you'd like, such as
/// keeping track of the number of all bytes allocated:
///
/// ```rust
/// use std::alloc::{System, GlobalAlloc, Layout};
/// use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
///
/// struct Counter;
///
/// static ALLOCATED: AtomicUsize = AtomicUsize::new(0);
///
/// unsafe impl GlobalAlloc for Counter {
///     unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
///         let ret = System.alloc(layout);
///         if !ret.is_null() {
///             ALLOCATED.fetch_add(layout.size(), SeqCst);
///         }
///         return ret
///     }
///
///     unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
///         System.dealloc(ptr, layout);
///         ALLOCATED.fetch_sub(layout.size(), SeqCst);
///     }
/// }
///
/// #[global_allocator]
/// static A: Counter = Counter;
///
/// fn main() {
///     println!("allocated bytes before main: {}", ALLOCATED.load(SeqCst));
/// }
/// ```
///
/// It can also be used directly to allocate memory independently of whatever
/// global allocator has been selected for a Rust program. For example if a Rust
/// program opts in to using jemalloc as the global allocator, `System` will
/// still allocate memory using `malloc` and `HeapAlloc`.
#[stable(feature = "alloc_system_type", since = "1.28.0")]
#[derive(Debug, Default, Copy, Clone)]
pub struct System;

// The AllocRef impl checks the layout size to be non-zero and forwards to the GlobalAlloc impl,
// which is in `std::sys::*::alloc`.
#[unstable(feature = "allocator_api", issue = "32838")]
unsafe impl AllocRef for System {
    #[inline]
    fn alloc(&mut self, layout: Layout) -> Result<NonNull<[u8]>, AllocErr> {
        let size = layout.size();
        let ptr = if size == 0 {
            layout.dangling()
        } else {
            // SAFETY: `layout` is non-zero in size,
            unsafe { NonNull::new(GlobalAlloc::alloc(&System, layout)).ok_or(AllocErr)? }
        };
        Ok(NonNull::slice_from_raw_parts(ptr, size))
    }

    #[inline]
    fn alloc_zeroed(&mut self, layout: Layout) -> Result<NonNull<[u8]>, AllocErr> {
        let size = layout.size();
        let ptr = if size == 0 {
            layout.dangling()
        } else {
            // SAFETY: `layout` is non-zero in size,
            unsafe { NonNull::new(GlobalAlloc::alloc_zeroed(&System, layout)).ok_or(AllocErr)? }
        };
        Ok(NonNull::slice_from_raw_parts(ptr, size))
    }

    #[inline]
    unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) {
        if layout.size() != 0 {
            // SAFETY: `layout` is non-zero in size,
            // other conditions must be upheld by the caller
            unsafe { GlobalAlloc::dealloc(&System, ptr.as_ptr(), layout) }
        }
    }

    #[inline]
    unsafe fn grow(
        &mut self,
        ptr: NonNull<u8>,
        layout: Layout,
        new_size: usize,
    ) -> Result<NonNull<[u8]>, AllocErr> {
        debug_assert!(
            new_size >= layout.size(),
            "`new_size` must be greater than or equal to `layout.size()`"
        );

        // SAFETY: `new_size` must be non-zero, which is checked in the match expression.
        // Other conditions must be upheld by the caller
        unsafe {
            match layout.size() {
                old_size if old_size == new_size => {
                    Ok(NonNull::slice_from_raw_parts(ptr, new_size))
                }
                0 => self.alloc(Layout::from_size_align_unchecked(new_size, layout.align())),
                old_size => {
                    // `realloc` probably checks for `new_size > size` or something similar.
                    intrinsics::assume(new_size > old_size);
                    let raw_ptr = GlobalAlloc::realloc(&System, ptr.as_ptr(), layout, new_size);
                    let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?;
                    Ok(NonNull::slice_from_raw_parts(ptr, new_size))
                }
            }
        }
    }

    #[inline]
    unsafe fn grow_zeroed(
        &mut self,
        ptr: NonNull<u8>,
        layout: Layout,
        new_size: usize,
    ) -> Result<NonNull<[u8]>, AllocErr> {
        debug_assert!(
            new_size >= layout.size(),
            "`new_size` must be greater than or equal to `layout.size()`"
        );

        // SAFETY: `new_size` must be non-zero, which is checked in the match expression.
        // Other conditions must be upheld by the caller
        unsafe {
            match layout.size() {
                old_size if old_size == new_size => {
                    Ok(NonNull::slice_from_raw_parts(ptr, new_size))
                }
                0 => self.alloc_zeroed(Layout::from_size_align_unchecked(new_size, layout.align())),
                old_size => {
                    // `realloc` probably checks for `new_size > size` or something similar.
                    intrinsics::assume(new_size > old_size);
                    let raw_ptr = GlobalAlloc::realloc(&System, ptr.as_ptr(), layout, new_size);
                    raw_ptr.add(old_size).write_bytes(0, new_size - old_size);
                    let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?;
                    Ok(NonNull::slice_from_raw_parts(ptr, new_size))
                }
            }
        }
    }

    #[inline]
    unsafe fn shrink(
        &mut self,
        ptr: NonNull<u8>,
        layout: Layout,
        new_size: usize,
    ) -> Result<NonNull<[u8]>, AllocErr> {
        let old_size = layout.size();
        debug_assert!(
            new_size <= old_size,
            "`new_size` must be smaller than or equal to `layout.size()`"
        );

        let ptr = if new_size == old_size {
            ptr
        } else if new_size == 0 {
            // SAFETY: `layout` is non-zero in size as `old_size` != `new_size`
            // Other conditions must be upheld by the caller
            unsafe {
                self.dealloc(ptr, layout);
            }
            layout.dangling()
        } else {
            // SAFETY: new_size is not zero,
            // Other conditions must be upheld by the caller
            let raw_ptr = unsafe {
                // `realloc` probably checks for `new_size < old_size` or something similar.
                intrinsics::assume(new_size < old_size);
                GlobalAlloc::realloc(&System, ptr.as_ptr(), layout, new_size)
            };
            NonNull::new(raw_ptr).ok_or(AllocErr)?
        };

        Ok(NonNull::slice_from_raw_parts(ptr, new_size))
    }
}
static HOOK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut());

/// Registers a custom allocation error hook, replacing any that was previously registered.
///
/// The allocation error hook is invoked when an infallible memory allocation fails, before
/// the runtime aborts. The default hook prints a message to standard error,
/// but this behavior can be customized with the [`set_alloc_error_hook`] and
/// [`take_alloc_error_hook`] functions.
///
/// The hook is provided with a `Layout` struct which contains information
/// about the allocation that failed.
///
/// The allocation error hook is a global resource.
///
/// [`set_alloc_error_hook`]: fn.set_alloc_error_hook.html
/// [`take_alloc_error_hook`]: fn.take_alloc_error_hook.html
#[unstable(feature = "alloc_error_hook", issue = "51245")]
pub fn set_alloc_error_hook(hook: fn(Layout)) {
    HOOK.store(hook as *mut (), Ordering::SeqCst);
}

/// Unregisters the current allocation error hook, returning it.
///
/// *See also the function [`set_alloc_error_hook`].*
///
/// If no custom hook is registered, the default hook will be returned.
///
/// [`set_alloc_error_hook`]: fn.set_alloc_error_hook.html
#[unstable(feature = "alloc_error_hook", issue = "51245")]
pub fn take_alloc_error_hook() -> fn(Layout) {
    let hook = HOOK.swap(ptr::null_mut(), Ordering::SeqCst);
    if hook.is_null() { default_alloc_error_hook } else { unsafe { mem::transmute(hook) } }
}

fn default_alloc_error_hook(layout: Layout) {
    dumb_print(format_args!("memory allocation of {} bytes failed", layout.size()));
}

#[cfg(not(test))]
#[doc(hidden)]
#[alloc_error_handler]
#[unstable(feature = "alloc_internals", issue = "none")]
pub fn rust_oom(layout: Layout) -> ! {
    let hook = HOOK.load(Ordering::SeqCst);
    let hook: fn(Layout) =
        if hook.is_null() { default_alloc_error_hook } else { unsafe { mem::transmute(hook) } };
    hook(layout);
    crate::process::abort()
}

#[cfg(not(test))]
#[doc(hidden)]
#[allow(unused_attributes)]
#[unstable(feature = "alloc_internals", issue = "none")]
pub mod __default_lib_allocator {
    use super::{GlobalAlloc, Layout, System};
    // These magic symbol names are used as a fallback for implementing the
    // `__rust_alloc` etc symbols (see `src/liballoc/alloc.rs`) when there is
    // no `#[global_allocator]` attribute.

    // for symbol names src/librustc_ast/expand/allocator.rs
    // for signatures src/librustc_allocator/lib.rs

    // linkage directives are provided as part of the current compiler allocator
    // ABI

    #[rustc_std_internal_symbol]
    pub unsafe extern "C" fn __rdl_alloc(size: usize, align: usize) -> *mut u8 {
        // SAFETY: see the guarantees expected by `Layout::from_size_align` and
        // `GlobalAlloc::alloc`.
        unsafe {
            let layout = Layout::from_size_align_unchecked(size, align);
            System.alloc(layout)
        }
    }

    #[rustc_std_internal_symbol]
    pub unsafe extern "C" fn __rdl_dealloc(ptr: *mut u8, size: usize, align: usize) {
        // SAFETY: see the guarantees expected by `Layout::from_size_align` and
        // `GlobalAlloc::dealloc`.
        unsafe { System.dealloc(ptr, Layout::from_size_align_unchecked(size, align)) }
    }

    #[rustc_std_internal_symbol]
    pub unsafe extern "C" fn __rdl_realloc(
        ptr: *mut u8,
        old_size: usize,
        align: usize,
        new_size: usize,
    ) -> *mut u8 {
        // SAFETY: see the guarantees expected by `Layout::from_size_align` and
        // `GlobalAlloc::realloc`.
        unsafe {
            let old_layout = Layout::from_size_align_unchecked(old_size, align);
            System.realloc(ptr, old_layout, new_size)
        }
    }

    #[rustc_std_internal_symbol]
    pub unsafe extern "C" fn __rdl_alloc_zeroed(size: usize, align: usize) -> *mut u8 {
        // SAFETY: see the guarantees expected by `Layout::from_size_align` and
        // `GlobalAlloc::alloc_zeroed`.
        unsafe {
            let layout = Layout::from_size_align_unchecked(size, align);
            System.alloc_zeroed(layout)
        }
    }
}
<commit_msg>Switch to intra-doc links for std/src/alloc.rs<commit_after>//! Memory allocation APIs
//!
//! In a given program, the standard library has one “global” memory allocator
//! that is used for example by `Box<T>` and `Vec<T>`.
//!
//! Currently the default global allocator is unspecified. Libraries, however,
//! like `cdylib`s and `staticlib`s are guaranteed to use the [`System`] by
//! default.
//!
//! # The `#[global_allocator]` attribute
//!
//! This attribute allows configuring the choice of global allocator.
//! You can use this to implement a completely custom global allocator
//! to route all default allocation requests to a custom object.
//!
//! ```rust
//! use std::alloc::{GlobalAlloc, System, Layout};
//!
//! struct MyAllocator;
//!
//! unsafe impl GlobalAlloc for MyAllocator {
//!     unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
//!         System.alloc(layout)
//!     }
//!
//!     unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
//!         System.dealloc(ptr, layout)
//!     }
//! }
//!
//! #[global_allocator]
//! static GLOBAL: MyAllocator = MyAllocator;
//!
//! fn main() {
//!     // This `Vec` will allocate memory through `GLOBAL` above
//!     let mut v = Vec::new();
//!     v.push(1);
//! }
//! ```
//!
//! The attribute is used on a `static` item whose type implements the
//! [`GlobalAlloc`] trait. This type can be provided by an external library:
//!
//! ```rust,ignore (demonstrates crates.io usage)
//! extern crate jemallocator;
//!
//! use jemallocator::Jemalloc;
//!
//! #[global_allocator]
//! static GLOBAL: Jemalloc = Jemalloc;
//!
//! fn main() {}
//! ```
//!
//! The `#[global_allocator]` can only be used once in a crate
//! or its recursive dependencies.

#![deny(unsafe_op_in_unsafe_fn)]
#![stable(feature = "alloc_module", since = "1.28.0")]

use core::intrinsics;
use core::ptr::NonNull;
use core::sync::atomic::{AtomicPtr, Ordering};
use core::{mem, ptr};

use crate::sys_common::util::dumb_print;

#[stable(feature = "alloc_module", since = "1.28.0")]
#[doc(inline)]
pub use alloc_crate::alloc::*;

/// The default memory allocator provided by the operating system.
///
/// This is based on `malloc` on Unix platforms and `HeapAlloc` on Windows,
/// plus related functions.
///
/// This type implements the `GlobalAlloc` trait and Rust programs by default
/// work as if they had this definition:
///
/// ```rust
/// use std::alloc::System;
///
/// #[global_allocator]
/// static A: System = System;
///
/// fn main() {
///     let a = Box::new(4); // Allocates from the system allocator.
///     println!("{}", a);
/// }
/// ```
///
/// You can also define your own wrapper around `System` if you'd like, such as
/// keeping track of the number of all bytes allocated:
///
/// ```rust
/// use std::alloc::{System, GlobalAlloc, Layout};
/// use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
///
/// struct Counter;
///
/// static ALLOCATED: AtomicUsize = AtomicUsize::new(0);
///
/// unsafe impl GlobalAlloc for Counter {
///     unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
///         let ret = System.alloc(layout);
///         if !ret.is_null() {
///             ALLOCATED.fetch_add(layout.size(), SeqCst);
///         }
///         return ret
///     }
///
///     unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
///         System.dealloc(ptr, layout);
///         ALLOCATED.fetch_sub(layout.size(), SeqCst);
///     }
/// }
///
/// #[global_allocator]
/// static A: Counter = Counter;
///
/// fn main() {
///     println!("allocated bytes before main: {}", ALLOCATED.load(SeqCst));
/// }
/// ```
///
/// It can also be used directly to allocate memory independently of whatever
/// global allocator has been selected for a Rust program. For example if a Rust
/// program opts in to using jemalloc as the global allocator, `System` will
/// still allocate memory using `malloc` and `HeapAlloc`.
#[stable(feature = "alloc_system_type", since = "1.28.0")]
#[derive(Debug, Default, Copy, Clone)]
pub struct System;

// The AllocRef impl checks the layout size to be non-zero and forwards to the GlobalAlloc impl,
// which is in `std::sys::*::alloc`.
#[unstable(feature = "allocator_api", issue = "32838")]
unsafe impl AllocRef for System {
    #[inline]
    fn alloc(&mut self, layout: Layout) -> Result<NonNull<[u8]>, AllocErr> {
        let size = layout.size();
        let ptr = if size == 0 {
            layout.dangling()
        } else {
            // SAFETY: `layout` is non-zero in size,
            unsafe { NonNull::new(GlobalAlloc::alloc(&System, layout)).ok_or(AllocErr)? }
        };
        Ok(NonNull::slice_from_raw_parts(ptr, size))
    }

    #[inline]
    fn alloc_zeroed(&mut self, layout: Layout) -> Result<NonNull<[u8]>, AllocErr> {
        let size = layout.size();
        let ptr = if size == 0 {
            layout.dangling()
        } else {
            // SAFETY: `layout` is non-zero in size,
            unsafe { NonNull::new(GlobalAlloc::alloc_zeroed(&System, layout)).ok_or(AllocErr)? }
        };
        Ok(NonNull::slice_from_raw_parts(ptr, size))
    }

    #[inline]
    unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) {
        if layout.size() != 0 {
            // SAFETY: `layout` is non-zero in size,
            // other conditions must be upheld by the caller
            unsafe { GlobalAlloc::dealloc(&System, ptr.as_ptr(), layout) }
        }
    }

    #[inline]
    unsafe fn grow(
        &mut self,
        ptr: NonNull<u8>,
        layout: Layout,
        new_size: usize,
    ) -> Result<NonNull<[u8]>, AllocErr> {
        debug_assert!(
            new_size >= layout.size(),
            "`new_size` must be greater than or equal to `layout.size()`"
        );

        // SAFETY: `new_size` must be non-zero, which is checked in the match expression.
        // Other conditions must be upheld by the caller
        unsafe {
            match layout.size() {
                old_size if old_size == new_size => {
                    Ok(NonNull::slice_from_raw_parts(ptr, new_size))
                }
                0 => self.alloc(Layout::from_size_align_unchecked(new_size, layout.align())),
                old_size => {
                    // `realloc` probably checks for `new_size > size` or something similar.
                    intrinsics::assume(new_size > old_size);
                    let raw_ptr = GlobalAlloc::realloc(&System, ptr.as_ptr(), layout, new_size);
                    let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?;
                    Ok(NonNull::slice_from_raw_parts(ptr, new_size))
                }
            }
        }
    }

    #[inline]
    unsafe fn grow_zeroed(
        &mut self,
        ptr: NonNull<u8>,
        layout: Layout,
        new_size: usize,
    ) -> Result<NonNull<[u8]>, AllocErr> {
        debug_assert!(
            new_size >= layout.size(),
            "`new_size` must be greater than or equal to `layout.size()`"
        );

        // SAFETY: `new_size` must be non-zero, which is checked in the match expression.
        // Other conditions must be upheld by the caller
        unsafe {
            match layout.size() {
                old_size if old_size == new_size => {
                    Ok(NonNull::slice_from_raw_parts(ptr, new_size))
                }
                0 => self.alloc_zeroed(Layout::from_size_align_unchecked(new_size, layout.align())),
                old_size => {
                    // `realloc` probably checks for `new_size > size` or something similar.
                    intrinsics::assume(new_size > old_size);
                    let raw_ptr = GlobalAlloc::realloc(&System, ptr.as_ptr(), layout, new_size);
                    raw_ptr.add(old_size).write_bytes(0, new_size - old_size);
                    let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?;
                    Ok(NonNull::slice_from_raw_parts(ptr, new_size))
                }
            }
        }
    }

    #[inline]
    unsafe fn shrink(
        &mut self,
        ptr: NonNull<u8>,
        layout: Layout,
        new_size: usize,
    ) -> Result<NonNull<[u8]>, AllocErr> {
        let old_size = layout.size();
        debug_assert!(
            new_size <= old_size,
            "`new_size` must be smaller than or equal to `layout.size()`"
        );

        let ptr = if new_size == old_size {
            ptr
        } else if new_size == 0 {
            // SAFETY: `layout` is non-zero in size as `old_size` != `new_size`
            // Other conditions must be upheld by the caller
            unsafe {
                self.dealloc(ptr, layout);
            }
            layout.dangling()
        } else {
            // SAFETY: new_size is not zero,
            // Other conditions must be upheld by the caller
            let raw_ptr = unsafe {
                // `realloc` probably checks for `new_size < old_size` or something similar.
                intrinsics::assume(new_size < old_size);
                GlobalAlloc::realloc(&System, ptr.as_ptr(), layout, new_size)
            };
            NonNull::new(raw_ptr).ok_or(AllocErr)?
        };

        Ok(NonNull::slice_from_raw_parts(ptr, new_size))
    }
}
static HOOK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut());

/// Registers a custom allocation error hook, replacing any that was previously registered.
///
/// The allocation error hook is invoked when an infallible memory allocation fails, before
/// the runtime aborts. The default hook prints a message to standard error,
/// but this behavior can be customized with the [`set_alloc_error_hook`] and
/// [`take_alloc_error_hook`] functions.
///
/// The hook is provided with a `Layout` struct which contains information
/// about the allocation that failed.
///
/// The allocation error hook is a global resource.
#[unstable(feature = "alloc_error_hook", issue = "51245")]
pub fn set_alloc_error_hook(hook: fn(Layout)) {
    HOOK.store(hook as *mut (), Ordering::SeqCst);
}

/// Unregisters the current allocation error hook, returning it.
///
/// *See also the function [`set_alloc_error_hook`].*
///
/// If no custom hook is registered, the default hook will be returned.
#[unstable(feature = "alloc_error_hook", issue = "51245")]
pub fn take_alloc_error_hook() -> fn(Layout) {
    let hook = HOOK.swap(ptr::null_mut(), Ordering::SeqCst);
    if hook.is_null() { default_alloc_error_hook } else { unsafe { mem::transmute(hook) } }
}

fn default_alloc_error_hook(layout: Layout) {
    dumb_print(format_args!("memory allocation of {} bytes failed", layout.size()));
}

#[cfg(not(test))]
#[doc(hidden)]
#[alloc_error_handler]
#[unstable(feature = "alloc_internals", issue = "none")]
pub fn rust_oom(layout: Layout) -> ! {
    let hook = HOOK.load(Ordering::SeqCst);
    let hook: fn(Layout) =
        if hook.is_null() { default_alloc_error_hook } else { unsafe { mem::transmute(hook) } };
    hook(layout);
    crate::process::abort()
}

#[cfg(not(test))]
#[doc(hidden)]
#[allow(unused_attributes)]
#[unstable(feature = "alloc_internals", issue = "none")]
pub mod __default_lib_allocator {
    use super::{GlobalAlloc, Layout, System};
    // These magic symbol names are used as a fallback for implementing the
    // `__rust_alloc` etc symbols (see `src/liballoc/alloc.rs`) when there is
    // no `#[global_allocator]` attribute.

    // for symbol names src/librustc_ast/expand/allocator.rs
    // for signatures src/librustc_allocator/lib.rs

    // linkage directives are provided as part of the current compiler allocator
    // ABI

    #[rustc_std_internal_symbol]
    pub unsafe extern "C" fn __rdl_alloc(size: usize, align: usize) -> *mut u8 {
        // SAFETY: see the guarantees expected by `Layout::from_size_align` and
        // `GlobalAlloc::alloc`.
        unsafe {
            let layout = Layout::from_size_align_unchecked(size, align);
            System.alloc(layout)
        }
    }

    #[rustc_std_internal_symbol]
    pub unsafe extern "C" fn __rdl_dealloc(ptr: *mut u8, size: usize, align: usize) {
        // SAFETY: see the guarantees expected by `Layout::from_size_align` and
        // `GlobalAlloc::dealloc`.
        unsafe { System.dealloc(ptr, Layout::from_size_align_unchecked(size, align)) }
    }

    #[rustc_std_internal_symbol]
    pub unsafe extern "C" fn __rdl_realloc(
        ptr: *mut u8,
        old_size: usize,
        align: usize,
        new_size: usize,
    ) -> *mut u8 {
        // SAFETY: see the guarantees expected by `Layout::from_size_align` and
        // `GlobalAlloc::realloc`.
        unsafe {
            let old_layout = Layout::from_size_align_unchecked(old_size, align);
            System.realloc(ptr, old_layout, new_size)
        }
    }

    #[rustc_std_internal_symbol]
    pub unsafe extern "C" fn __rdl_alloc_zeroed(size: usize, align: usize) -> *mut u8 {
        // SAFETY: see the guarantees expected by `Layout::from_size_align` and
        // `GlobalAlloc::alloc_zeroed`.
        unsafe {
            let layout = Layout::from_size_align_unchecked(size, align);
            System.alloc_zeroed(layout)
        }
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]
use utils;
pub struct Memory
{
    ram: [u8;0x10000],
    rom: [u8;0x10000],
    // bank switching flags
    basic_on: bool,
    chargen_on: bool,
    io_on: bool,
    kernal_on: bool,
    cart_lo_on: bool, // cart flag - unused for now
    cart_hi_on: bool  // cart flag - unused for now
}

impl Memory
{
    pub fn new() -> Memory
    {
        let mut memory = Memory
        {
            ram: [0;0x10000],   // 64k
            rom: [0;0x10000],   // store ROM data in 64k array so it's easier to address it with bank switching
            basic_on: false,
            chargen_on: false,
            io_on: false,
            kernal_on: false,
            cart_lo_on: false, // unused for now
            cart_hi_on: false, // unused for now
        };

        // load basic
        let mut start_addr: u32 = 0xA000;
        let basic = utils::open_file("rom/basic.rom");

        for (i,addr) in (start_addr..0xC000).enumerate()
        {
            memory.rom[addr as usize] = basic[i as usize];
        }

        // load chargen
        start_addr = 0xD000;
        let chargen = utils::open_file("rom/chargen.rom");

        for (i,addr) in (start_addr..0xE000).enumerate()
        {
            memory.rom[addr as usize] = chargen[i as usize];
        }

        // load kernal
        start_addr = 0xE000;
        let kernal = utils::open_file("rom/kernal.rom");

        for (i,addr) in (start_addr..0x10000).enumerate()
        {
            memory.rom[addr as usize] = kernal[i as usize];
        }

        memory
    }

    pub fn get_bank(&mut self, addr: u16) -> &mut [u8]
    {
        match addr
        {
            0x0000...0x9FFF => &mut self.ram[0..0x10000],
            0xA000...0xCFFF => if self.basic_on   { &mut self.rom[0..0x10000] } else { &mut self.ram[0..0x10000] },
            0xD000...0xDFFF => if self.chargen_on { &mut self.rom[0..0x10000] } else { &mut self.ram[0..0x10000] },
            0xE000...0xFFFF => if self.kernal_on  { &mut self.rom[0..0x10000] } else { &mut self.ram[0..0x10000] },
            _ => panic!("Address out of memory range")
        }
    }

    pub fn reset(&mut self)
    {
        self.write_byte(0x0000, 0xFF);
        self.write_byte(0x0001, 0x07); // enable kernal, chargen and basic access
    }

    fn update_bank_flags(&mut self)
    {
        // latch state is determined by 5 least significant bits from this location
        let latch = self.ram[0x0001] & 0x1F;

        // default to RAM only
        self.basic_on = false;
        self.chargen_on = false;
        self.io_on = false;
        self.kernal_on = false;
        self.cart_lo_on = false;
        self.cart_hi_on = false;

        match latch
        {
            0x02 => {
                self.chargen_on = true;
                self.kernal_on = true;
                self.cart_hi_on = true;
            },
            0x03 => {
                self.chargen_on = true;
                self.kernal_on = true;
                self.cart_lo_on = true;
                self.cart_hi_on = true;
            }
            0x05 | 0x0D | 0x1D => {
                self.io_on = true;
            }
            0x06 => {
                self.cart_hi_on = true;
                self.io_on = true;
            },
            0x07 => {
                self.cart_lo_on = true;
                self.cart_hi_on = true;
                self.io_on = true;
                self.kernal_on = true;
            },
            0x0B => {
                self.cart_lo_on = true;
                self.basic_on = true;
                self.chargen_on = true;
                self.kernal_on = true;
            },
            0x0F => {
                self.cart_lo_on = true;
                self.basic_on = true;
                self.io_on = true;
                self.kernal_on = true;
            },
            0x10...0x17 => {
                self.cart_lo_on = true;
                self.io_on = true;
                self.cart_hi_on = true;
            },
            0x19 | 0x09 => {
                self.chargen_on = true;
            },
            0x1A | 0x0A => {
                self.chargen_on = true;
                self.kernal_on = true;
            },
            0x1B => {
                self.basic_on = true;
                self.chargen_on = true;
                self.kernal_on = true;
            },
            0xE | 0x1E => {
                self.io_on = true;
                self.kernal_on = true;
            },
            0x1F => {
                self.basic_on = true;
                self.io_on = true;
                self.kernal_on = true;
            },
            _ => ()
        }
    }

    // Write a byte to memory
    pub fn write_byte(&mut self, addr: u16, value: u8)
    {
        // parentheses to avoid borrowing issues with changing the flags
        {
            let bank = self.get_bank(addr);
            bank[addr as usize] = value;
        }

        // update the bank switching flags here, since they can only change on memory write
        // latch byte changed - update bank switching flags
        if addr == 0x0001 { self.update_bank_flags(); }
    }

    // Read a byte from memory
    pub fn read_byte(&mut self, addr: u16) -> u8
    {
        let bank = self.get_bank(addr);
        bank[addr as usize]
    }

    // Read a word from memory (stored in little endian)
    pub fn read_word_le(&mut self, addr: u16) -> u16
    {
        let bank = self.get_bank(addr);
        let value_be: u16 = ((bank[addr as usize] as u16) << 8 & 0xFF00) |
                            ((bank[(addr + 0x0001) as usize] as u16) & 0x00FF);

        let value_le: u16 = ((value_be << 8) & 0xFF00) | ((value_be >> 8) & 0x00FF);
        value_le
    }

    // Read a word from memory (stored in big endian: swap low<->high)
    pub fn read_word_be(&mut self, addr: u16) -> u16
    {
        let bank = self.get_bank(addr);
        let value_le: u16 = ((bank[addr as usize] as u16) << 8 & 0xFF00) |
                            ((bank[(addr + 0x0001) as usize] as u16) & 0x00FF);
        value_le
    }

    // Write word in little endian format (low/high)
    pub fn write_word_le(&mut self, addr: u16, value: u16)
    {
        let bank = self.get_bank(addr);
        let value_le_lo: u8 = (((value << 8) & 0xFF00) >> 8 & 0xFF) as u8;
        let value_le_hi: u8 = ((value >> 8) & 0x00FF) as u8;

        bank[addr as usize] = value_le_lo;
        bank[(addr + 0x0001) as usize] = value_le_hi;
    }

    // Write word in big endian format (high/low)
    pub fn write_word_be(&mut self, addr: u16, value: u16)
    {
        let bank = self.get_bank(addr);
        let value_le_lo: u8 = (((value << 8) & 0xFF00) >> 8 & 0xFF) as u8;
        let value_le_hi: u8 = ((value >> 8) & 0x00FF) as u8;

        bank[addr as usize] = value_le_hi;
        bank[(addr + 0x0001) as usize] = value_le_lo;
    }
}

<commit_msg>call write_byte() in write_word() to correctly update latch flags<commit_after>#![allow(dead_code)]
use utils;
pub struct Memory
{
    ram: [u8;0x10000],
    rom: [u8;0x10000],
    // bank switching flags
    basic_on: bool,
    chargen_on: bool,
    io_on: bool,
    kernal_on: bool,
    cart_lo_on: bool, // cart flag - unused for now
    cart_hi_on: bool  // cart flag - unused for now
}

impl Memory
{
    pub fn new() -> Memory
    {
        let mut memory = Memory
        {
            ram: [0;0x10000],   // 64k
            rom: [0;0x10000],   // store ROM data in 64k array so it's easier to address it with bank switching
            basic_on: false,
            chargen_on: false,
            io_on: false,
            kernal_on: false,
            cart_lo_on: false, // unused for now
            cart_hi_on: false, // unused for now
        };

        // load basic
        let mut start_addr: u32 = 0xA000;
        let basic = utils::open_file("rom/basic.rom");

        for (i,addr) in (start_addr..0xC000).enumerate()
        {
            memory.rom[addr as usize] = basic[i as usize];
        }

        // load chargen
        start_addr = 0xD000;
        let chargen = utils::open_file("rom/chargen.rom");

        for (i,addr) in (start_addr..0xE000).enumerate()
        {
            memory.rom[addr as usize] = chargen[i as usize];
        }

        // load kernal
        start_addr = 0xE000;
        let kernal = utils::open_file("rom/kernal.rom");

        for (i,addr) in (start_addr..0x10000).enumerate()
        {
            memory.rom[addr as usize] = kernal[i as usize];
        }

        memory
    }

    pub fn get_bank(&mut self, addr: u16) -> &mut [u8]
    {
        match addr
        {
            0x0000...0x9FFF => &mut self.ram[0..0x10000],
            0xA000...0xCFFF => if self.basic_on   { &mut self.rom[0..0x10000] } else { &mut self.ram[0..0x10000] },
            0xD000...0xDFFF => if self.chargen_on { &mut self.rom[0..0x10000] } else { &mut self.ram[0..0x10000] },
            0xE000...0xFFFF => if self.kernal_on  { &mut self.rom[0..0x10000] } else { &mut self.ram[0..0x10000] },
            _ => panic!("Address out of memory range")
        }
    }

    pub fn reset(&mut self)
    {
        self.write_byte(0x0000, 0xFF);
        self.write_byte(0x0001, 0x07); // enable kernal, chargen and basic access
    }

    fn update_bank_flags(&mut self)
    {
        // latch state is determined by 5 least significant bits from this location
        let latch = self.ram[0x0001] & 0x1F;

        // default to RAM only
        self.basic_on = false;
        self.chargen_on = false;
        self.io_on = false;
        self.kernal_on = false;
        self.cart_lo_on = false;
        self.cart_hi_on = false;

        match latch
        {
            0x02 => {
                self.chargen_on = true;
                self.kernal_on = true;
                self.cart_hi_on = true;
            },
            0x03 => {
                self.chargen_on = true;
                self.kernal_on = true;
                self.cart_lo_on = true;
                self.cart_hi_on = true;
            }
            0x05 | 0x0D | 0x1D => {
                self.io_on = true;
            }
            0x06 => {
                self.cart_hi_on = true;
                self.io_on = true;
            },
            0x07 => {
                self.cart_lo_on = true;
                self.cart_hi_on = true;
                self.io_on = true;
                self.kernal_on = true;
            },
            0x0B => {
                self.cart_lo_on = true;
                self.basic_on = true;
                self.chargen_on = true;
                self.kernal_on = true;
            },
            0x0F => {
                self.cart_lo_on = true;
                self.basic_on = true;
                self.io_on = true;
                self.kernal_on = true;
            },
            0x10...0x17 => {
                self.cart_lo_on = true;
                self.io_on = true;
                self.cart_hi_on = true;
            },
            0x19 | 0x09 => {
                self.chargen_on = true;
            },
            0x1A | 0x0A => {
                self.chargen_on = true;
                self.kernal_on = true;
            },
            0x1B => {
                self.basic_on = true;
                self.chargen_on = true;
                self.kernal_on = true;
            },
            0xE | 0x1E => {
                self.io_on = true;
                self.kernal_on = true;
            },
            0x1F => {
                self.basic_on = true;
                self.io_on = true;
                self.kernal_on = true;
            },
            _ => ()
        }
    }

    // Write a byte to memory
    pub fn write_byte(&mut self, addr: u16, value: u8)
    {
        // parentheses to avoid borrowing issues with changing the flags
        {
            let bank = self.get_bank(addr);
            bank[addr as usize] = value;
        }

        // update the bank switching flags here, since they can only change on memory write
        // latch byte changed - update bank switching flags
        if addr == 0x0001 { self.update_bank_flags(); }
    }

    // Read a byte from memory
    pub fn read_byte(&mut self, addr: u16) -> u8
    {
        let bank = self.get_bank(addr);
        bank[addr as usize]
    }

    // Read a word from memory (stored in little endian)
    pub fn read_word_le(&mut self, addr: u16) -> u16
    {
        let bank = self.get_bank(addr);
        let value_be: u16 = ((bank[addr as usize] as u16) << 8 & 0xFF00) |
                            ((bank[(addr + 0x0001) as usize] as u16) & 0x00FF);

        let value_le: u16 = ((value_be << 8) & 0xFF00) | ((value_be >> 8) & 0x00FF);
        value_le
    }

    // Read a word from memory (stored in big endian: swap low<->high)
    pub fn read_word_be(&mut self, addr: u16) -> u16
    {
        let bank = self.get_bank(addr);
        let value_le: u16 = ((bank[addr as usize] as u16) << 8 & 0xFF00) |
                            ((bank[(addr + 0x0001) as usize] as u16) & 0x00FF);
        value_le
    }

    // Write word in little endian format (low/high)
    pub fn write_word_le(&mut self, addr: u16, value: u16)
    {
        let value_le_lo: u8 = (((value << 8) & 0xFF00) >> 8 & 0xFF) as u8;
        let value_le_hi: u8 = ((value >> 8) & 0x00FF) as u8;

        self.write_byte(addr, value_le_lo);
        self.write_byte(addr + 0x0001, value_le_hi);
    }

    // Write word in big endian format (high/low)
    pub fn write_word_be(&mut self, addr: u16, value: u16)
    {
        let value_le_lo: u8 = (((value << 8) & 0xFF00) >> 8 & 0xFF) as u8;
        let value_le_hi: u8 = ((value >> 8) & 0x00FF) as u8;

        self.write_byte(addr, value_le_hi);
        self.write_byte(addr + 0x0001, value_le_lo);
    }
}

<|endoftext|>