<commit_before>use crate::{
    message::BasicReturnMessage,
    pinky_swear::{PinkyBroadcaster, PinkySwear},
    publisher_confirm::Confirmation,
    BasicProperties,
};
use log::error;
use parking_lot::Mutex;
use std::{collections::VecDeque, sync::Arc};

#[derive(Clone, Debug, Default)]
pub(crate) struct ReturnedMessages {
    inner: Arc<Mutex<Inner>>,
}

impl ReturnedMessages {
    pub(crate) fn start_new_delivery(&self, message: BasicReturnMessage) {
        self.inner.lock().current_message = Some(message);
    }

    pub(crate) fn set_delivery_properties(&self, properties: BasicProperties) {
        if let Some(message) = self.inner.lock().current_message.as_mut() {
            message.delivery.properties = properties;
        }
    }

    pub(crate) fn new_delivery_complete(&self) {
        self.inner.lock().new_delivery_complete();
    }

    pub(crate) fn receive_delivery_content(&self, data: Vec<u8>) {
        if let Some(message) = self.inner.lock().current_message.as_mut() {
            message.delivery.data.extend(data);
        }
    }

    pub(crate) fn drain(&self) -> Vec<BasicReturnMessage> {
        self.inner.lock().drain()
    }

    pub(crate) fn register_pinky(&self, pinky: PinkyBroadcaster<Confirmation>) {
        self.inner.lock().register_pinky(pinky);
    }

    pub(crate) fn register_dropped_confirm(&self, promise: PinkySwear<Confirmation>) {
        self.inner.lock().register_dropped_confirm(promise);
    }
}

#[derive(Debug, Default)]
pub struct Inner {
    current_message: Option<BasicReturnMessage>,
    waiting_messages: VecDeque<BasicReturnMessage>,
    messages: Vec<BasicReturnMessage>,
    dropped_confirms: Vec<PinkySwear<Confirmation>>,
    pinkies: VecDeque<PinkyBroadcaster<Confirmation>>,
}

impl Inner {
    fn register_pinky(&mut self, pinky: PinkyBroadcaster<Confirmation>) {
        if let Some(message) = self.waiting_messages.pop_front() {
            pinky.swear(Confirmation::Nack(message));
        } else {
            self.pinkies.push_back(pinky);
        }
    }

    fn register_dropped_confirm(&mut self, promise: PinkySwear<Confirmation>) {
        if let Some(confirmation) = promise.try_wait() {
            if let Confirmation::Nack(message) = confirmation {
                self.messages.push(message);
            }
        } else {
            self.dropped_confirms.push(promise);
        }
    }

    fn new_delivery_complete(&mut self) {
        if let Some(message) = self.current_message.take() {
            error!("Server returned us a message: {:?}", message);
            if let Some(pinky) = self.pinkies.pop_front() {
                pinky.swear(Confirmation::Nack(message));
            } else {
                self.waiting_messages.push_back(message);
            }
        }
    }

    fn drain(&mut self) -> Vec<BasicReturnMessage> {
        let mut messages = self.messages.drain(..).collect::<Vec<BasicReturnMessage>>();
        for promise in self
            .dropped_confirms
            .drain(..)
            .collect::<Vec<PinkySwear<Confirmation>>>()
        {
            if let Some(confirmation) = promise.try_wait() {
                if let Confirmation::Nack(message) = confirmation {
                    messages.push(message);
                }
            } else {
                self.dropped_confirms.push(promise);
            }
        }
        messages
    }
}
<commit_msg>use std::mem::take instead of drain + collect<commit_after>use crate::{
    message::BasicReturnMessage,
    pinky_swear::{PinkyBroadcaster, PinkySwear},
    publisher_confirm::Confirmation,
    BasicProperties,
};
use log::error;
use parking_lot::Mutex;
use std::{collections::VecDeque, sync::Arc};

#[derive(Clone, Debug, Default)]
pub(crate) struct ReturnedMessages {
    inner: Arc<Mutex<Inner>>,
}

impl ReturnedMessages {
    pub(crate) fn start_new_delivery(&self, message: BasicReturnMessage) {
        self.inner.lock().current_message = Some(message);
    }

    pub(crate) fn set_delivery_properties(&self, properties: BasicProperties) {
        if let Some(message) = self.inner.lock().current_message.as_mut() {
            message.delivery.properties = properties;
        }
    }

    pub(crate) fn new_delivery_complete(&self) {
        self.inner.lock().new_delivery_complete();
    }

    pub(crate) fn receive_delivery_content(&self, data: Vec<u8>) {
        if let Some(message) = self.inner.lock().current_message.as_mut() {
            message.delivery.data.extend(data);
        }
    }

    pub(crate) fn drain(&self) -> Vec<BasicReturnMessage> {
        self.inner.lock().drain()
    }

    pub(crate) fn register_pinky(&self, pinky: PinkyBroadcaster<Confirmation>) {
        self.inner.lock().register_pinky(pinky);
    }

    pub(crate) fn register_dropped_confirm(&self, promise: PinkySwear<Confirmation>) {
        self.inner.lock().register_dropped_confirm(promise);
    }
}

#[derive(Debug, Default)]
pub struct Inner {
    current_message: Option<BasicReturnMessage>,
    waiting_messages: VecDeque<BasicReturnMessage>,
    messages: Vec<BasicReturnMessage>,
    dropped_confirms: Vec<PinkySwear<Confirmation>>,
    pinkies: VecDeque<PinkyBroadcaster<Confirmation>>,
}

impl Inner {
    fn register_pinky(&mut self, pinky: PinkyBroadcaster<Confirmation>) {
        if let Some(message) = self.waiting_messages.pop_front() {
            pinky.swear(Confirmation::Nack(message));
        } else {
            self.pinkies.push_back(pinky);
        }
    }

    fn register_dropped_confirm(&mut self, promise: PinkySwear<Confirmation>) {
        if let Some(confirmation) = promise.try_wait() {
            if let Confirmation::Nack(message) = confirmation {
                self.messages.push(message);
            }
        } else {
            self.dropped_confirms.push(promise);
        }
    }

    fn new_delivery_complete(&mut self) {
        if let Some(message) = self.current_message.take() {
            error!("Server returned us a message: {:?}", message);
            if let Some(pinky) = self.pinkies.pop_front() {
                pinky.swear(Confirmation::Nack(message));
            } else {
                self.waiting_messages.push_back(message);
            }
        }
    }

    fn drain(&mut self) -> Vec<BasicReturnMessage> {
        let mut messages = std::mem::take(&mut self.messages);
        for promise in std::mem::take(&mut self.dropped_confirms) {
            if let Some(confirmation) = promise.try_wait() {
                if let Confirmation::Nack(message) = confirmation {
                    messages.push(message);
                }
            } else {
                self.dropped_confirms.push(promise);
            }
        }
        messages
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 Johannes Köster.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

//! Fasta reading and writing.

use std::io;
use std::io::prelude::*;
use std::ascii::AsciiExt;

pub struct FastaReader<R: io::Read> {
    reader: io::BufReader<R>,
    line: String
}

impl<R: io::Read> FastaReader<R> {
    /// Create a new FastQ reader.
    pub fn new(reader: R) -> Self {
        FastaReader { reader: io::BufReader::new(reader), line: String::new() }
    }

    pub fn read(&mut self, record: &mut Record) -> io::Result<()> {
        record.clear();
        if self.line.is_empty() {
            try!(self.reader.read_line(&mut self.line));
            if self.line.is_empty() {
                return Ok(());
            }
        }

        if !self.line.starts_with(">") {
            return Err(io::Error::new(
                io::ErrorKind::Other,
                "Expected > at record start.",
                None,
            ));
        }
        record.header.push_str(&self.line);
        loop {
            self.line.clear();
            try!(self.reader.read_line(&mut self.line));
            record.seq.push_str(&self.line.trim_right());
            if self.line.is_empty() || self.line.starts_with(">") {
                break;
            }
        }

        Ok(())
    }

    /// Return an iterator over the records of this FastQ file.
    pub fn records(self) -> Records<R> {
        Records { reader: self }
    }
}

impl<R: io::Read + io::Seek> FastaReader<R> {
    /// Seek to a given offset. Intended for internal use by IndexedFastaReader.
    fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
        self.reader.get_mut().seek(pos)
    }
}

pub struct Record {
    header: String,
    seq: String,
}

impl Record {
    pub fn new() -> Self {
        Record { header: String::new(), seq: String::new() }
    }

    pub fn is_empty(&self) -> bool {
        self.header.is_empty() && self.seq.is_empty()
    }

    /// Check validity of Fasta record.
    pub fn check(&self) -> Result<(), &str> {
        if self.id().is_none() {
            return Err("Expecting id for FastQ record.");
        }
        if !self.seq.is_ascii() {
            return Err("Non-ascii character found in sequence.");
        }

        Ok(())
    }

    /// Return the id of the record.
    pub fn id(&self) -> Option<&str> {
        self.header[1..].words().next()
    }

    /// Return descriptions if present.
    pub fn desc(&self) -> Vec<&str> {
        self.header[1..].words().skip(1).collect()
    }

    /// Return the sequence of the record.
    pub fn seq(&self) -> &[u8] {
        self.seq.as_bytes()
    }

    fn clear(&mut self) {
        self.header.clear();
        self.seq.clear();
    }
}

/// An iterator over the records of a Fasta file.
pub struct Records<R: io::Read> {
    reader: FastaReader<R>,
}

impl<R: io::Read> Iterator for Records<R> {
    type Item = io::Result<Record>;

    fn next(&mut self) -> Option<io::Result<Record>> {
        let mut record = Record::new();
        match self.reader.read(&mut record) {
            Ok(()) if record.is_empty() => None,
            Ok(())   => Some(Ok(record)),
            Err(err) => Some(Err(err))
        }
    }
}

/// A Fasta writer.
pub struct FastaWriter<W: io::Write> {
    writer: io::BufWriter<W>,
}

impl<W: io::Write> FastaWriter<W> {
    /// Create a new Fasta writer.
    pub fn new(writer: W) -> Self {
        FastaWriter { writer: io::BufWriter::new(writer) }
    }

    /// Directly write a Fasta record.
    pub fn write_record(&mut self, record: Record) -> io::Result<()> {
        self.write(record.id().unwrap_or(""), &record.desc(), record.seq())
    }

    /// Write a Fasta record with given values.
    ///
    /// # Arguments
    ///
    /// * `id` - the record id
    /// * `desc` - the optional descriptions
    /// * `seq` - the sequence
    pub fn write(&mut self, id: &str, desc: &[&str], seq: &[u8]) -> io::Result<()> {
        try!(self.writer.write(b">"));
        try!(self.writer.write(id.as_bytes()));
        if !desc.is_empty() {
            for d in desc {
                try!(self.writer.write(b" "));
                try!(self.writer.write(d.as_bytes()));
            }
        }
        try!(self.writer.write(b"\n"));
        try!(self.writer.write(seq));
        try!(self.writer.write(b"\n"));

        Ok(())
    }

    /// Flush the writer, ensuring that everything is written.
    pub fn flush(&mut self) -> io::Result<()> {
        self.writer.flush()
    }
}

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

    const FASTA_FILE: &'static [u8] = b">id desc
ACCGTAGGCTGA
";

    #[test]
    fn test_reader() {
        let reader = FastaReader::new(FASTA_FILE);
        let records: Vec<io::Result<Record>> = reader.records().collect();
        assert!(records.len() == 1);
        for res in records {
            let record = res.ok().unwrap();
            assert_eq!(record.check(), Ok(()));
            assert_eq!(record.id(), Some("id"));
            assert_eq!(record.desc(), ["desc"]);
            assert_eq!(record.seq(), b"ACCGTAGGCTGA");
        }
    }

    #[test]
    fn test_writer() {
        let mut writer = FastaWriter::new(Vec::new());
        writer.write("id", &["desc"], b"ACCGTAGGCTGA").ok().expect("Expected successful write");
        writer.flush().ok().expect("Expected successful write");
        assert_eq!(writer.writer.get_ref(), &FASTA_FILE);
    }
}
<commit_msg>Authors.<commit_after>// Copyright 2014 Johannes Köster, Christopher Schröder.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

//! Fasta reading and writing.

use std::io;
use std::io::prelude::*;
use std::ascii::AsciiExt;

pub struct FastaReader<R: io::Read> {
    reader: io::BufReader<R>,
    line: String
}

impl<R: io::Read> FastaReader<R> {
    /// Create a new FastQ reader.
    pub fn new(reader: R) -> Self {
        FastaReader { reader: io::BufReader::new(reader), line: String::new() }
    }

    pub fn read(&mut self, record: &mut Record) -> io::Result<()> {
        record.clear();
        if self.line.is_empty() {
            try!(self.reader.read_line(&mut self.line));
            if self.line.is_empty() {
                return Ok(());
            }
        }

        if !self.line.starts_with(">") {
            return Err(io::Error::new(
                io::ErrorKind::Other,
                "Expected > at record start.",
                None,
            ));
        }
        record.header.push_str(&self.line);
        loop {
            self.line.clear();
            try!(self.reader.read_line(&mut self.line));
            record.seq.push_str(&self.line.trim_right());
            if self.line.is_empty() || self.line.starts_with(">") {
                break;
            }
        }

        Ok(())
    }

    /// Return an iterator over the records of this FastQ file.
    pub fn records(self) -> Records<R> {
        Records { reader: self }
    }
}

impl<R: io::Read + io::Seek> FastaReader<R> {
    /// Seek to a given offset. Intended for internal use by IndexedFastaReader.
    fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
        self.reader.get_mut().seek(pos)
    }
}

pub struct Record {
    header: String,
    seq: String,
}

impl Record {
    pub fn new() -> Self {
        Record { header: String::new(), seq: String::new() }
    }

    pub fn is_empty(&self) -> bool {
        self.header.is_empty() && self.seq.is_empty()
    }

    /// Check validity of Fasta record.
    pub fn check(&self) -> Result<(), &str> {
        if self.id().is_none() {
            return Err("Expecting id for FastQ record.");
        }
        if !self.seq.is_ascii() {
            return Err("Non-ascii character found in sequence.");
        }

        Ok(())
    }

    /// Return the id of the record.
    pub fn id(&self) -> Option<&str> {
        self.header[1..].words().next()
    }

    /// Return descriptions if present.
    pub fn desc(&self) -> Vec<&str> {
        self.header[1..].words().skip(1).collect()
    }

    /// Return the sequence of the record.
    pub fn seq(&self) -> &[u8] {
        self.seq.as_bytes()
    }

    fn clear(&mut self) {
        self.header.clear();
        self.seq.clear();
    }
}

/// An iterator over the records of a Fasta file.
pub struct Records<R: io::Read> {
    reader: FastaReader<R>,
}

impl<R: io::Read> Iterator for Records<R> {
    type Item = io::Result<Record>;

    fn next(&mut self) -> Option<io::Result<Record>> {
        let mut record = Record::new();
        match self.reader.read(&mut record) {
            Ok(()) if record.is_empty() => None,
            Ok(())   => Some(Ok(record)),
            Err(err) => Some(Err(err))
        }
    }
}

/// A Fasta writer.
pub struct FastaWriter<W: io::Write> {
    writer: io::BufWriter<W>,
}

impl<W: io::Write> FastaWriter<W> {
    /// Create a new Fasta writer.
    pub fn new(writer: W) -> Self {
        FastaWriter { writer: io::BufWriter::new(writer) }
    }

    /// Directly write a Fasta record.
    pub fn write_record(&mut self, record: Record) -> io::Result<()> {
        self.write(record.id().unwrap_or(""), &record.desc(), record.seq())
    }

    /// Write a Fasta record with given values.
    ///
    /// # Arguments
    ///
    /// * `id` - the record id
    /// * `desc` - the optional descriptions
    /// * `seq` - the sequence
    pub fn write(&mut self, id: &str, desc: &[&str], seq: &[u8]) -> io::Result<()> {
        try!(self.writer.write(b">"));
        try!(self.writer.write(id.as_bytes()));
        if !desc.is_empty() {
            for d in desc {
                try!(self.writer.write(b" "));
                try!(self.writer.write(d.as_bytes()));
            }
        }
        try!(self.writer.write(b"\n"));
        try!(self.writer.write(seq));
        try!(self.writer.write(b"\n"));

        Ok(())
    }

    /// Flush the writer, ensuring that everything is written.
    pub fn flush(&mut self) -> io::Result<()> {
        self.writer.flush()
    }
}

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

    const FASTA_FILE: &'static [u8] = b">id desc
ACCGTAGGCTGA
";

    #[test]
    fn test_reader() {
        let reader = FastaReader::new(FASTA_FILE);
        let records: Vec<io::Result<Record>> = reader.records().collect();
        assert!(records.len() == 1);
        for res in records {
            let record = res.ok().unwrap();
            assert_eq!(record.check(), Ok(()));
            assert_eq!(record.id(), Some("id"));
            assert_eq!(record.desc(), ["desc"]);
            assert_eq!(record.seq(), b"ACCGTAGGCTGA");
        }
    }

    #[test]
    fn test_writer() {
        let mut writer = FastaWriter::new(Vec::new());
        writer.write("id", &["desc"], b"ACCGTAGGCTGA").ok().expect("Expected successful write");
        writer.flush().ok().expect("Expected successful write");
        assert_eq!(writer.writer.get_ref(), &FASTA_FILE);
    }
}
<|endoftext|>


<commit_before>
import driver::session;
import middle::trans::base;
import middle::trans::common::{T_fn, T_i1, T_i8, T_i32,
                               T_int, T_nil,
                               T_opaque_vec, T_ptr, T_unique_ptr,
                               T_size_t, T_void, T_vec2};
import lib::llvm::{type_names, ModuleRef, ValueRef, TypeRef};

type upcalls =
    {_fail: ValueRef,
     trace: ValueRef,
     malloc: ValueRef,
     free: ValueRef,
     exchange_malloc: ValueRef,
     exchange_free: ValueRef,
     validate_box: ValueRef,
     mark: ValueRef,
     str_new_uniq: ValueRef,
     str_new_shared: ValueRef,
     cmp_type: ValueRef,
     log_type: ValueRef,
     alloc_c_stack: ValueRef,
     call_shim_on_c_stack: ValueRef,
     call_shim_on_rust_stack: ValueRef,
     rust_personality: ValueRef,
     reset_stack_limit: ValueRef};

fn declare_upcalls(targ_cfg: @session::config,
                   _tn: type_names,
                   tydesc_type: TypeRef,
                   llmod: ModuleRef) -> @upcalls {
    fn decl(llmod: ModuleRef, prefix: ~str, name: ~str,
            tys: ~[TypeRef], rv: TypeRef) ->
       ValueRef {
        let mut arg_tys: ~[TypeRef] = ~[];
        for tys.each |t| { vec::push(arg_tys, t); }
        let fn_ty = T_fn(arg_tys, rv);
        return base::decl_cdecl_fn(llmod, prefix + name, fn_ty);
    }
    fn nothrow(f: ValueRef) -> ValueRef {
        base::set_no_unwind(f); f
    }
    let d = |a,b,c| decl(llmod, ~"upcall_", a, b, c);
    let dv = |a,b| decl(llmod, ~"upcall_", a, b, T_void());

    let int_t = T_int(targ_cfg);
    let size_t = T_size_t(targ_cfg);

    return @{_fail: dv(~"fail", ~[T_ptr(T_i8()),
                             T_ptr(T_i8()),
                             size_t]),
          trace: dv(~"trace", ~[T_ptr(T_i8()),
                              T_ptr(T_i8()),
                              int_t]),
          malloc:
              nothrow(d(~"malloc",
                        ~[T_ptr(tydesc_type), int_t],
                        T_ptr(T_i8()))),
          free:
              nothrow(dv(~"free", ~[T_ptr(T_i8())])),
          exchange_malloc:
              nothrow(d(~"exchange_malloc",
                        ~[T_ptr(tydesc_type), int_t],
                        T_ptr(T_i8()))),
          exchange_free:
              nothrow(dv(~"exchange_free", ~[T_ptr(T_i8())])),
          validate_box:
              nothrow(dv(~"validate_box", ~[T_ptr(T_i8())])),
          mark:
              d(~"mark", ~[T_ptr(T_i8())], int_t),
          str_new_uniq:
              nothrow(d(~"str_new_uniq", ~[T_ptr(T_i8()), int_t],
                        T_ptr(T_i8()))),
          str_new_shared:
              nothrow(d(~"str_new_shared", ~[T_ptr(T_i8()), int_t],
                        T_ptr(T_i8()))),
          cmp_type:
              dv(~"cmp_type",
                 ~[T_ptr(T_i1()), T_ptr(tydesc_type),
                  T_ptr(T_i8()),
                  T_ptr(T_i8()),
                  T_i8()]),
          log_type:
              dv(~"log_type", ~[T_ptr(tydesc_type),
                              T_ptr(T_i8()), T_i32()]),
          alloc_c_stack:
              d(~"alloc_c_stack", ~[size_t], T_ptr(T_i8())),
          call_shim_on_c_stack:
              d(~"call_shim_on_c_stack",
                // arguments: void *args, void *fn_ptr
                ~[T_ptr(T_i8()), T_ptr(T_i8())],
                int_t),
          call_shim_on_rust_stack:
              d(~"call_shim_on_rust_stack",
                ~[T_ptr(T_i8()), T_ptr(T_i8())], int_t),
          rust_personality:
              nothrow(d(~"rust_personality", ~[], T_i32())),
          reset_stack_limit:
              nothrow(dv(~"reset_stack_limit", ~[]))
         };
}
//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
//
<commit_msg>rustc: upcall_alloc_c_stack doesn't exist<commit_after>
import driver::session;
import middle::trans::base;
import middle::trans::common::{T_fn, T_i1, T_i8, T_i32,
                               T_int, T_nil,
                               T_opaque_vec, T_ptr, T_unique_ptr,
                               T_size_t, T_void, T_vec2};
import lib::llvm::{type_names, ModuleRef, ValueRef, TypeRef};

type upcalls =
    {_fail: ValueRef,
     trace: ValueRef,
     malloc: ValueRef,
     free: ValueRef,
     exchange_malloc: ValueRef,
     exchange_free: ValueRef,
     validate_box: ValueRef,
     mark: ValueRef,
     str_new_uniq: ValueRef,
     str_new_shared: ValueRef,
     cmp_type: ValueRef,
     log_type: ValueRef,
     call_shim_on_c_stack: ValueRef,
     call_shim_on_rust_stack: ValueRef,
     rust_personality: ValueRef,
     reset_stack_limit: ValueRef};

fn declare_upcalls(targ_cfg: @session::config,
                   _tn: type_names,
                   tydesc_type: TypeRef,
                   llmod: ModuleRef) -> @upcalls {
    fn decl(llmod: ModuleRef, prefix: ~str, name: ~str,
            tys: ~[TypeRef], rv: TypeRef) ->
       ValueRef {
        let mut arg_tys: ~[TypeRef] = ~[];
        for tys.each |t| { vec::push(arg_tys, t); }
        let fn_ty = T_fn(arg_tys, rv);
        return base::decl_cdecl_fn(llmod, prefix + name, fn_ty);
    }
    fn nothrow(f: ValueRef) -> ValueRef {
        base::set_no_unwind(f); f
    }
    let d = |a,b,c| decl(llmod, ~"upcall_", a, b, c);
    let dv = |a,b| decl(llmod, ~"upcall_", a, b, T_void());

    let int_t = T_int(targ_cfg);
    let size_t = T_size_t(targ_cfg);

    return @{_fail: dv(~"fail", ~[T_ptr(T_i8()),
                             T_ptr(T_i8()),
                             size_t]),
          trace: dv(~"trace", ~[T_ptr(T_i8()),
                              T_ptr(T_i8()),
                              int_t]),
          malloc:
              nothrow(d(~"malloc",
                        ~[T_ptr(tydesc_type), int_t],
                        T_ptr(T_i8()))),
          free:
              nothrow(dv(~"free", ~[T_ptr(T_i8())])),
          exchange_malloc:
              nothrow(d(~"exchange_malloc",
                        ~[T_ptr(tydesc_type), int_t],
                        T_ptr(T_i8()))),
          exchange_free:
              nothrow(dv(~"exchange_free", ~[T_ptr(T_i8())])),
          validate_box:
              nothrow(dv(~"validate_box", ~[T_ptr(T_i8())])),
          mark:
              d(~"mark", ~[T_ptr(T_i8())], int_t),
          str_new_uniq:
              nothrow(d(~"str_new_uniq", ~[T_ptr(T_i8()), int_t],
                        T_ptr(T_i8()))),
          str_new_shared:
              nothrow(d(~"str_new_shared", ~[T_ptr(T_i8()), int_t],
                        T_ptr(T_i8()))),
          cmp_type:
              dv(~"cmp_type",
                 ~[T_ptr(T_i1()), T_ptr(tydesc_type),
                  T_ptr(T_i8()),
                  T_ptr(T_i8()),
                  T_i8()]),
          log_type:
              dv(~"log_type", ~[T_ptr(tydesc_type),
                              T_ptr(T_i8()), T_i32()]),
          call_shim_on_c_stack:
              d(~"call_shim_on_c_stack",
                // arguments: void *args, void *fn_ptr
                ~[T_ptr(T_i8()), T_ptr(T_i8())],
                int_t),
          call_shim_on_rust_stack:
              d(~"call_shim_on_rust_stack",
                ~[T_ptr(T_i8()), T_ptr(T_i8())], int_t),
          rust_personality:
              nothrow(d(~"rust_personality", ~[], T_i32())),
          reset_stack_limit:
              nothrow(dv(~"reset_stack_limit", ~[]))
         };
}
//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
//
<|endoftext|>


<commit_before><commit_msg>simplifying tests with unwrap<commit_after><|endoftext|>


<commit_before>//! This pass checks HIR bodies that may be evaluated at compile-time (e.g., `const`, `static`,
//! `const fn`) for structured control flow (e.g. `if`, `while`), which is forbidden in a const
//! context.
//!
//! By the time the MIR const-checker runs, these high-level constructs have been lowered to
//! control-flow primitives (e.g., `Goto`, `SwitchInt`), making it tough to properly attribute
//! errors. We still look for those primitives in the MIR const-checker to ensure nothing slips
//! through, but errors for structured control flow in a `const` should be emitted here.

use rustc_attr as attr;
use rustc_data_structures::stable_set::FxHashSet;
use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_middle::hir::map::Map;
use rustc_middle::ty;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_session::parse::feature_err;
use rustc_span::{sym, Span, Symbol};

/// An expression that is not *always* legal in a const context.
#[derive(Clone, Copy)]
enum NonConstExpr {
    Loop(hir::LoopSource),
    Match(hir::MatchSource),
}

impl NonConstExpr {
    fn name(self) -> String {
        match self {
            Self::Loop(src) => format!("`{}`", src.name()),
            Self::Match(src) => format!("`{}`", src.name()),
        }
    }

    fn required_feature_gates(self) -> Option<&'static [Symbol]> {
        use hir::LoopSource::*;
        use hir::MatchSource::*;

        let gates: &[_] = match self {
            Self::Match(AwaitDesugar) => {
                return None;
            }

            Self::Loop(ForLoop) | Self::Match(ForLoopDesugar) => &[sym::const_for],

            Self::Match(TryDesugar) => &[sym::const_try],

            // All other expressions are allowed.
            Self::Loop(Loop | While) | Self::Match(Normal) => &[],
        };

        Some(gates)
    }
}

fn check_mod_const_bodies(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
    let mut vis = CheckConstVisitor::new(tcx);
    tcx.hir().visit_item_likes_in_module(module_def_id, &mut vis.as_deep_visitor());
    tcx.hir().visit_item_likes_in_module(module_def_id, &mut CheckConstTraitVisitor::new(tcx));
}

pub(crate) fn provide(providers: &mut Providers) {
    *providers = Providers { check_mod_const_bodies, ..*providers };
}

struct CheckConstTraitVisitor<'tcx> {
    tcx: TyCtxt<'tcx>,
}

impl<'tcx> CheckConstTraitVisitor<'tcx> {
    fn new(tcx: TyCtxt<'tcx>) -> Self {
        CheckConstTraitVisitor { tcx }
    }
}

impl<'tcx> hir::itemlikevisit::ItemLikeVisitor<'tcx> for CheckConstTraitVisitor<'tcx> {
    /// check for const trait impls, and errors if the impl uses provided/default functions
    /// of the trait being implemented; as those provided functions can be non-const.
    fn visit_item(&mut self, item: &'hir hir::Item<'hir>) {
        let _: Option<_> = try {
            if let hir::ItemKind::Impl(ref imp) = item.kind {
                if let hir::Constness::Const = imp.constness {
                    let did = imp.of_trait.as_ref()?.trait_def_id()?;
                    let mut to_implement = FxHashSet::default();

                    for did in self.tcx.associated_item_def_ids(did) {
                        if let ty::AssocItem {
                            kind: ty::AssocKind::Fn, ident, defaultness, ..
                        } = self.tcx.associated_item(*did)
                        {
                            // we can ignore functions that do not have default bodies:
                            // if those are unimplemented it will be catched by typeck.
                            if defaultness.has_value()
                                && !self.tcx.has_attr(*did, sym::default_method_body_is_const)
                            {
                                to_implement.insert(ident);
                            }
                        }
                    }

                    for it in imp
                        .items
                        .iter()
                        .filter(|it| matches!(it.kind, hir::AssocItemKind::Fn { .. }))
                    {
                        to_implement.remove(&it.ident);
                    }

                    // all nonconst trait functions (not marked with #[default_method_body_is_const])
                    // must be implemented
                    if !to_implement.is_empty() {
                        self.tcx
                            .sess
                            .struct_span_err(
                                item.span,
                                "const trait implementations may not use non-const default functions",
                            )
                            .note(&format!("`{}` not implemented", to_implement.into_iter().map(|id| id.to_string()).collect::<Vec<_>>().join("`, `")))
                            .emit();
                    }
                }
            }
        };
    }

    fn visit_trait_item(&mut self, _: &'hir hir::TraitItem<'hir>) {}

    fn visit_impl_item(&mut self, _: &'hir hir::ImplItem<'hir>) {}

    fn visit_foreign_item(&mut self, _: &'hir hir::ForeignItem<'hir>) {}
}

#[derive(Copy, Clone)]
struct CheckConstVisitor<'tcx> {
    tcx: TyCtxt<'tcx>,
    const_kind: Option<hir::ConstContext>,
    def_id: Option<LocalDefId>,
}

impl<'tcx> CheckConstVisitor<'tcx> {
    fn new(tcx: TyCtxt<'tcx>) -> Self {
        CheckConstVisitor { tcx, const_kind: None, def_id: None }
    }

    /// Emits an error when an unsupported expression is found in a const context.
    fn const_check_violated(&self, expr: NonConstExpr, span: Span) {
        let Self { tcx, def_id, const_kind } = *self;

        let features = tcx.features();
        let required_gates = expr.required_feature_gates();

        let is_feature_allowed = |feature_gate| {
            // All features require that the corresponding gate be enabled,
            // even if the function has `#[rustc_allow_const_fn_unstable(the_gate)]`.
            if !tcx.features().enabled(feature_gate) {
                return false;
            }

            // If `def_id` is `None`, we don't need to consider stability attributes.
            let def_id = match def_id {
                Some(x) => x.to_def_id(),
                None => return true,
            };

            // If this crate is not using stability attributes, or this function is not claiming to be a
            // stable `const fn`, that is all that is required.
            if !tcx.features().staged_api || tcx.has_attr(def_id, sym::rustc_const_unstable) {
                return true;
            }

            // However, we cannot allow stable `const fn`s to use unstable features without an explicit
            // opt-in via `rustc_allow_const_fn_unstable`.
            attr::rustc_allow_const_fn_unstable(&tcx.sess, &tcx.get_attrs(def_id))
                .any(|name| name == feature_gate)
        };

        match required_gates {
            // Don't emit an error if the user has enabled the requisite feature gates.
            Some(gates) if gates.iter().copied().all(is_feature_allowed) => return,

            // `-Zunleash-the-miri-inside-of-you` only works for expressions that don't have a
            // corresponding feature gate. This encourages nightly users to use feature gates when
            // possible.
            None if tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you => {
                tcx.sess.span_warn(span, "skipping const checks");
                return;
            }

            _ => {}
        }

        let const_kind =
            const_kind.expect("`const_check_violated` may only be called inside a const context");

        let msg = format!("{} is not allowed in a `{}`", expr.name(), const_kind.keyword_name());

        let required_gates = required_gates.unwrap_or(&[]);
        let missing_gates: Vec<_> =
            required_gates.iter().copied().filter(|&g| !features.enabled(g)).collect();

        match missing_gates.as_slice() {
            &[] => struct_span_err!(tcx.sess, span, E0744, "{}", msg).emit(),

            &[missing_primary, ref missing_secondary @ ..] => {
                let mut err = feature_err(&tcx.sess.parse_sess, missing_primary, span, &msg);

                // If multiple feature gates would be required to enable this expression, include
                // them as help messages. Don't emit a separate error for each missing feature gate.
                //
                // FIXME(ecstaticmorse): Maybe this could be incorporated into `feature_err`? This
                // is a pretty narrow case, however.
                if tcx.sess.is_nightly_build() {
                    for gate in missing_secondary {
                        let note = format!(
                            "add `#![feature({})]` to the crate attributes to enable",
                            gate,
                        );
                        err.help(&note);
                    }
                }

                err.emit();
            }
        }
    }

    /// Saves the parent `const_kind` before calling `f` and restores it afterwards.
    fn recurse_into(
        &mut self,
        kind: Option<hir::ConstContext>,
        def_id: Option<LocalDefId>,
        f: impl FnOnce(&mut Self),
    ) {
        let parent_def_id = self.def_id;
        let parent_kind = self.const_kind;
        self.def_id = def_id;
        self.const_kind = kind;
        f(self);
        self.def_id = parent_def_id;
        self.const_kind = parent_kind;
    }
}

impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> {
    type Map = Map<'tcx>;

    fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
        NestedVisitorMap::OnlyBodies(self.tcx.hir())
    }

    fn visit_anon_const(&mut self, anon: &'tcx hir::AnonConst) {
        let kind = Some(hir::ConstContext::Const);
        self.recurse_into(kind, None, |this| intravisit::walk_anon_const(this, anon));
    }

    fn visit_body(&mut self, body: &'tcx hir::Body<'tcx>) {
        let owner = self.tcx.hir().body_owner_def_id(body.id());
        let kind = self.tcx.hir().body_const_context(owner);
        self.recurse_into(kind, Some(owner), |this| intravisit::walk_body(this, body));
    }

    fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) {
        match &e.kind {
            // Skip the following checks if we are not currently in a const context.
            _ if self.const_kind.is_none() => {}

            hir::ExprKind::Loop(_, _, source, _) => {
                self.const_check_violated(NonConstExpr::Loop(*source), e.span);
            }

            hir::ExprKind::Match(_, _, source) => {
                let non_const_expr = match source {
                    // These are handled by `ExprKind::Loop` above.
                    hir::MatchSource::ForLoopDesugar => None,

                    _ => Some(NonConstExpr::Match(*source)),
                };

                if let Some(expr) = non_const_expr {
                    self.const_check_violated(expr, e.span);
                }
            }

            _ => {}
        }

        intravisit::walk_expr(self, e);
    }
}
<commit_msg>Use Ancestory to check default fn in const impl instead of comparing idents<commit_after>//! This pass checks HIR bodies that may be evaluated at compile-time (e.g., `const`, `static`,
//! `const fn`) for structured control flow (e.g. `if`, `while`), which is forbidden in a const
//! context.
//!
//! By the time the MIR const-checker runs, these high-level constructs have been lowered to
//! control-flow primitives (e.g., `Goto`, `SwitchInt`), making it tough to properly attribute
//! errors. We still look for those primitives in the MIR const-checker to ensure nothing slips
//! through, but errors for structured control flow in a `const` should be emitted here.

use rustc_attr as attr;
use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_middle::hir::map::Map;
use rustc_middle::ty;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_session::parse::feature_err;
use rustc_span::{sym, Span, Symbol};

/// An expression that is not *always* legal in a const context.
#[derive(Clone, Copy)]
enum NonConstExpr {
    Loop(hir::LoopSource),
    Match(hir::MatchSource),
}

impl NonConstExpr {
    fn name(self) -> String {
        match self {
            Self::Loop(src) => format!("`{}`", src.name()),
            Self::Match(src) => format!("`{}`", src.name()),
        }
    }

    fn required_feature_gates(self) -> Option<&'static [Symbol]> {
        use hir::LoopSource::*;
        use hir::MatchSource::*;

        let gates: &[_] = match self {
            Self::Match(AwaitDesugar) => {
                return None;
            }

            Self::Loop(ForLoop) | Self::Match(ForLoopDesugar) => &[sym::const_for],

            Self::Match(TryDesugar) => &[sym::const_try],

            // All other expressions are allowed.
            Self::Loop(Loop | While) | Self::Match(Normal) => &[],
        };

        Some(gates)
    }
}

fn check_mod_const_bodies(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
    let mut vis = CheckConstVisitor::new(tcx);
    tcx.hir().visit_item_likes_in_module(module_def_id, &mut vis.as_deep_visitor());
    tcx.hir().visit_item_likes_in_module(module_def_id, &mut CheckConstTraitVisitor::new(tcx));
}

pub(crate) fn provide(providers: &mut Providers) {
    *providers = Providers { check_mod_const_bodies, ..*providers };
}

struct CheckConstTraitVisitor<'tcx> {
    tcx: TyCtxt<'tcx>,
}

impl<'tcx> CheckConstTraitVisitor<'tcx> {
    fn new(tcx: TyCtxt<'tcx>) -> Self {
        CheckConstTraitVisitor { tcx }
    }
}

impl<'tcx> hir::itemlikevisit::ItemLikeVisitor<'tcx> for CheckConstTraitVisitor<'tcx> {
    /// check for const trait impls, and errors if the impl uses provided/default functions
    /// of the trait being implemented; as those provided functions can be non-const.
    fn visit_item(&mut self, item: &'hir hir::Item<'hir>) {
        let _: Option<_> = try {
            if let hir::ItemKind::Impl(ref imp) = item.kind {
                if let hir::Constness::Const = imp.constness {
                    let trait_def_id = imp.of_trait.as_ref()?.trait_def_id()?;
                    let ancestors = self
                        .tcx
                        .trait_def(trait_def_id)
                        .ancestors(self.tcx, item.def_id.to_def_id())
                        .ok()?;
                    let mut to_implement = Vec::new();

                    for trait_item in self.tcx.associated_items(trait_def_id).in_definition_order()
                    {
                        if let ty::AssocItem {
                            kind: ty::AssocKind::Fn, ident, defaultness, ..
                        } = trait_item
                        {
                            // we can ignore functions that do not have default bodies:
                            // if those are unimplemented it will be catched by typeck.
                            if !defaultness.has_value()
                                || self
                                    .tcx
                                    .has_attr(trait_item.def_id, sym::default_method_body_is_const)
                            {
                                continue;
                            }

                            let is_implemented = ancestors
                                .leaf_def(self.tcx, trait_item.ident, trait_item.kind)
                                .map(|node_item| !node_item.defining_node.is_from_trait())
                                .unwrap_or(false);

                            if !is_implemented {
                                to_implement.push(ident.to_string());
                            }
                        }
                    }

                    // all nonconst trait functions (not marked with #[default_method_body_is_const])
                    // must be implemented
                    if !to_implement.is_empty() {
                        self.tcx
                            .sess
                            .struct_span_err(
                                item.span,
                                "const trait implementations may not use non-const default functions",
                            )
                            .note(&format!("`{}` not implemented", to_implement.join("`, `")))
                            .emit();
                    }
                }
            }
        };
    }

    fn visit_trait_item(&mut self, _: &'hir hir::TraitItem<'hir>) {}

    fn visit_impl_item(&mut self, _: &'hir hir::ImplItem<'hir>) {}

    fn visit_foreign_item(&mut self, _: &'hir hir::ForeignItem<'hir>) {}
}

#[derive(Copy, Clone)]
struct CheckConstVisitor<'tcx> {
    tcx: TyCtxt<'tcx>,
    const_kind: Option<hir::ConstContext>,
    def_id: Option<LocalDefId>,
}

impl<'tcx> CheckConstVisitor<'tcx> {
    fn new(tcx: TyCtxt<'tcx>) -> Self {
        CheckConstVisitor { tcx, const_kind: None, def_id: None }
    }

    /// Emits an error when an unsupported expression is found in a const context.
    fn const_check_violated(&self, expr: NonConstExpr, span: Span) {
        let Self { tcx, def_id, const_kind } = *self;

        let features = tcx.features();
        let required_gates = expr.required_feature_gates();

        let is_feature_allowed = |feature_gate| {
            // All features require that the corresponding gate be enabled,
            // even if the function has `#[rustc_allow_const_fn_unstable(the_gate)]`.
            if !tcx.features().enabled(feature_gate) {
                return false;
            }

            // If `def_id` is `None`, we don't need to consider stability attributes.
            let def_id = match def_id {
                Some(x) => x.to_def_id(),
                None => return true,
            };

            // If this crate is not using stability attributes, or this function is not claiming to be a
            // stable `const fn`, that is all that is required.
            if !tcx.features().staged_api || tcx.has_attr(def_id, sym::rustc_const_unstable) {
                return true;
            }

            // However, we cannot allow stable `const fn`s to use unstable features without an explicit
            // opt-in via `rustc_allow_const_fn_unstable`.
            attr::rustc_allow_const_fn_unstable(&tcx.sess, &tcx.get_attrs(def_id))
                .any(|name| name == feature_gate)
        };

        match required_gates {
            // Don't emit an error if the user has enabled the requisite feature gates.
            Some(gates) if gates.iter().copied().all(is_feature_allowed) => return,

            // `-Zunleash-the-miri-inside-of-you` only works for expressions that don't have a
            // corresponding feature gate. This encourages nightly users to use feature gates when
            // possible.
            None if tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you => {
                tcx.sess.span_warn(span, "skipping const checks");
                return;
            }

            _ => {}
        }

        let const_kind =
            const_kind.expect("`const_check_violated` may only be called inside a const context");

        let msg = format!("{} is not allowed in a `{}`", expr.name(), const_kind.keyword_name());

        let required_gates = required_gates.unwrap_or(&[]);
        let missing_gates: Vec<_> =
            required_gates.iter().copied().filter(|&g| !features.enabled(g)).collect();

        match missing_gates.as_slice() {
            &[] => struct_span_err!(tcx.sess, span, E0744, "{}", msg).emit(),

            &[missing_primary, ref missing_secondary @ ..] => {
                let mut err = feature_err(&tcx.sess.parse_sess, missing_primary, span, &msg);

                // If multiple feature gates would be required to enable this expression, include
                // them as help messages. Don't emit a separate error for each missing feature gate.
                //
                // FIXME(ecstaticmorse): Maybe this could be incorporated into `feature_err`? This
                // is a pretty narrow case, however.
                if tcx.sess.is_nightly_build() {
                    for gate in missing_secondary {
                        let note = format!(
                            "add `#![feature({})]` to the crate attributes to enable",
                            gate,
                        );
                        err.help(&note);
                    }
                }

                err.emit();
            }
        }
    }

    /// Saves the parent `const_kind` before calling `f` and restores it afterwards.
    fn recurse_into(
        &mut self,
        kind: Option<hir::ConstContext>,
        def_id: Option<LocalDefId>,
        f: impl FnOnce(&mut Self),
    ) {
        let parent_def_id = self.def_id;
        let parent_kind = self.const_kind;
        self.def_id = def_id;
        self.const_kind = kind;
        f(self);
        self.def_id = parent_def_id;
        self.const_kind = parent_kind;
    }
}

impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> {
    type Map = Map<'tcx>;

    fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
        NestedVisitorMap::OnlyBodies(self.tcx.hir())
    }

    fn visit_anon_const(&mut self, anon: &'tcx hir::AnonConst) {
        let kind = Some(hir::ConstContext::Const);
        self.recurse_into(kind, None, |this| intravisit::walk_anon_const(this, anon));
    }

    fn visit_body(&mut self, body: &'tcx hir::Body<'tcx>) {
        let owner = self.tcx.hir().body_owner_def_id(body.id());
        let kind = self.tcx.hir().body_const_context(owner);
        self.recurse_into(kind, Some(owner), |this| intravisit::walk_body(this, body));
    }

    fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) {
        match &e.kind {
            // Skip the following checks if we are not currently in a const context.
            _ if self.const_kind.is_none() => {}

            hir::ExprKind::Loop(_, _, source, _) => {
                self.const_check_violated(NonConstExpr::Loop(*source), e.span);
            }

            hir::ExprKind::Match(_, _, source) => {
                let non_const_expr = match source {
                    // These are handled by `ExprKind::Loop` above.
                    hir::MatchSource::ForLoopDesugar => None,

                    _ => Some(NonConstExpr::Match(*source)),
                };

                if let Some(expr) = non_const_expr {
                    self.const_check_violated(expr, e.span);
                }
            }

            _ => {}
        }

        intravisit::walk_expr(self, e);
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

extern crate freetype;

use app_units::Au;
use font::{FontHandleMethods, FontMetrics, FontTableMethods};
use font::{FontTableTag, FractionalPixel};
use freetype::freetype::{FTErrorMethods, FT_F26Dot6, FT_Face, FT_FaceRec};
use freetype::freetype::{FT_Done_Face, FT_New_Memory_Face};
use freetype::freetype::{FT_Get_Char_Index, FT_Get_Postscript_Name};
use freetype::freetype::{FT_Get_Kerning, FT_Get_Sfnt_Table, FT_Load_Sfnt_Table};
use freetype::freetype::{FT_GlyphSlot, FT_Library, FT_Long, FT_ULong};
use freetype::freetype::{FT_KERNING_DEFAULT, FT_STYLE_FLAG_BOLD, FT_STYLE_FLAG_ITALIC};
use freetype::freetype::{FT_Load_Glyph, FT_Set_Char_Size};
use freetype::freetype::{FT_SizeRec, FT_Size_Metrics, FT_UInt, struct_FT_Vector_};
use freetype::freetype::{ft_sfnt_os2};
use freetype::tt_os2::TT_OS2;
use libc::c_char;
use platform::font_context::FontContextHandle;
use platform::font_template::FontTemplateData;
use std::sync::Arc;
use std::{mem, ptr};
use style::computed_values::{font_stretch, font_weight};
use text::glyph::GlyphId;
use text::util::{fixed_to_float, float_to_fixed};
use util::str::c_str_to_string;

fn float_to_fixed_ft(f: f64) -> i32 {
    float_to_fixed(6, f)
}

fn fixed_to_float_ft(f: i32) -> f64 {
    fixed_to_float(6, f)
}

pub struct FontTable {
    buffer: Vec<u8>,
}

impl FontTableMethods for FontTable {
    fn buffer(&self) -> &[u8] {
        &self.buffer
    }
}

#[derive(Debug)]
pub struct FontHandle {
    // The font binary. This must stay valid for the lifetime of the font,
    // if the font is created using FT_Memory_Face.
    font_data: Arc<FontTemplateData>,
    face: FT_Face,
    handle: FontContextHandle,
}

impl Drop for FontHandle {
    fn drop(&mut self) {
        assert!(!self.face.is_null());
        unsafe {
            if !FT_Done_Face(self.face).succeeded() {
                panic!("FT_Done_Face failed");
            }
        }
    }
}

impl FontHandleMethods for FontHandle {
    fn new_from_template(fctx: &FontContextHandle,
                       template: Arc<FontTemplateData>,
                       pt_size: Option<Au>)
                        -> Result<FontHandle, ()> {
        let ft_ctx: FT_Library = fctx.ctx.ctx;
        if ft_ctx.is_null() { return Err(()); }

        let face_result = create_face_from_buffer(ft_ctx, &template.bytes, pt_size);

        // TODO: this could be more simply written as result::chain
        // and moving buf into the struct ctor, but cant' move out of
        // captured binding.
        return match face_result {
            Ok(face) => {
              let handle = FontHandle {
                  face: face,
                  font_data: template.clone(),
                  handle: fctx.clone()
              };
              Ok(handle)
            }
            Err(()) => Err(())
        };

        fn create_face_from_buffer(lib: FT_Library, buffer: &[u8], pt_size: Option<Au>)
                                   -> Result<FT_Face, ()> {
            unsafe {
                let mut face: FT_Face = ptr::null_mut();
                let face_index = 0 as FT_Long;
                let result = FT_New_Memory_Face(lib, buffer.as_ptr(), buffer.len() as FT_Long,
                                                face_index, &mut face);

                if !result.succeeded() || face.is_null() {
                    return Err(());
                }
                match pt_size {
                    Some(s) => {
                        match FontHandle::set_char_size(face, s) {
                            Ok(_) => Ok(face),
                            Err(_) => Err(()),
                        }
                    }
                    None => Ok(face),
                }
            }
        }
    }
    fn template(&self) -> Arc<FontTemplateData> {
        self.font_data.clone()
    }
    fn family_name(&self) -> String {
        unsafe {
            c_str_to_string((*self.face).family_name as *const c_char)
        }
    }
    fn face_name(&self) -> String {
        unsafe {
            c_str_to_string(FT_Get_Postscript_Name(self.face) as *const c_char)
        }
    }
    fn is_italic(&self) -> bool {
        unsafe { (*self.face).style_flags & FT_STYLE_FLAG_ITALIC != 0 }
    }
    fn boldness(&self) -> font_weight::T {
        let default_weight = font_weight::T::Weight400;
        if unsafe { (*self.face).style_flags & FT_STYLE_FLAG_BOLD == 0 } {
            default_weight
        } else {
            unsafe {
                let os2 = FT_Get_Sfnt_Table(self.face, ft_sfnt_os2) as *mut TT_OS2;
                let valid = !os2.is_null() && (*os2).version != 0xffff;
                if valid {
                    let weight =(*os2).usWeightClass;
                    match weight {
                        1 | 100...199 => font_weight::T::Weight100,
                        2 | 200...299 => font_weight::T::Weight200,
                        3 | 300...399 => font_weight::T::Weight300,
                        4 | 400...499 => font_weight::T::Weight400,
                        5 | 500...599 => font_weight::T::Weight500,
                        6 | 600...699 => font_weight::T::Weight600,
                        7 | 700...799 => font_weight::T::Weight700,
                        8 | 800...899 => font_weight::T::Weight800,
                        9 | 900...999 => font_weight::T::Weight900,
                        _ => default_weight
                    }
                } else {
                    default_weight
                }
            }
        }
    }
    fn stretchiness(&self) -> font_stretch::T {
        // TODO(pcwalton): Implement this.
        font_stretch::T::normal
    }

    fn glyph_index(&self, codepoint: char) -> Option<GlyphId> {
        assert!(!self.face.is_null());
        unsafe {
            let idx = FT_Get_Char_Index(self.face, codepoint as FT_ULong);
            if idx != 0 as FT_UInt {
                Some(idx as GlyphId)
            } else {
                debug!("Invalid codepoint: {}", codepoint);
                None
            }
        }
    }

    fn glyph_h_kerning(&self, first_glyph: GlyphId, second_glyph: GlyphId)
                       -> FractionalPixel {
        assert!(!self.face.is_null());
        let mut delta = struct_FT_Vector_ { x: 0, y: 0 };
        unsafe {
            FT_Get_Kerning(self.face, first_glyph, second_glyph, FT_KERNING_DEFAULT, &mut delta);
        }
        fixed_to_float_ft(delta.x as i32)
    }

    fn glyph_h_advance(&self, glyph: GlyphId) -> Option<FractionalPixel> {
        assert!(!self.face.is_null());
        unsafe {
            let res =  FT_Load_Glyph(self.face, glyph as FT_UInt, 0);
            if res.succeeded() {
                let void_glyph = (*self.face).glyph;
                let slot: FT_GlyphSlot = mem::transmute(void_glyph);
                assert!(!slot.is_null());
                let advance = (*slot).metrics.horiAdvance;
                debug!("h_advance for {} is {}", glyph, advance);
                let advance = advance as i32;
                Some(fixed_to_float_ft(advance) as FractionalPixel)
            } else {
                debug!("Unable to load glyph {}. reason: {}", glyph, res);
                None
            }
        }
    }

    fn metrics(&self) -> FontMetrics {
        /* TODO(Issue #76): complete me */
        let face = self.face_rec_mut();

        let underline_size = self.font_units_to_au(face.underline_thickness as f64);
        let underline_offset = self.font_units_to_au(face.underline_position as f64);
        let em_size = self.font_units_to_au(face.units_per_EM as f64);
        let ascent = self.font_units_to_au(face.ascender as f64);
        let descent = self.font_units_to_au(face.descender as f64);
        let max_advance = self.font_units_to_au(face.max_advance_width as f64);

        // 'leading' is supposed to be the vertical distance between two baselines,
        // reflected by the height attribute in freetype.  On OS X (w/ CTFont),
        // leading represents the distance between the bottom of a line descent to
        // the top of the next line's ascent or: (line_height - ascent - descent),
        // see http://stackoverflow.com/a/5635981 for CTFont implementation.
        // Convert using a formula similar to what CTFont returns for consistency.
        let height = self.font_units_to_au(face.height as f64);
        let leading = height - (ascent + descent);

        let mut strikeout_size = Au(0);
        let mut strikeout_offset = Au(0);
        let mut x_height = Au(0);
        unsafe {
            let os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2) as *mut TT_OS2;
            let valid = !os2.is_null() && (*os2).version != 0xffff;
            if valid {
               strikeout_size = self.font_units_to_au((*os2).yStrikeoutSize as f64);
               strikeout_offset = self.font_units_to_au((*os2).yStrikeoutPosition as f64);
               x_height = self.font_units_to_au((*os2).sxHeight as f64);
            }
        }

        let average_advance = self.glyph_index('0')
                                  .and_then(|idx| self.glyph_h_advance(idx))
                                  .map_or(max_advance, |advance| self.font_units_to_au(advance));

        let metrics = FontMetrics {
            underline_size:   underline_size,
            underline_offset: underline_offset,
            strikeout_size:   strikeout_size,
            strikeout_offset: strikeout_offset,
            leading:          leading,
            x_height:         x_height,
            em_size:          em_size,
            ascent:           ascent,
            descent:          -descent, // linux font's seem to use the opposite sign from mac
            max_advance:      max_advance,
            average_advance:  average_advance,
            line_gap:         height,
        };

        debug!("Font metrics (@{}px): {:?}", em_size.to_f32_px(), metrics);
        metrics
    }

    fn table_for_tag(&self, tag: FontTableTag) -> Option<FontTable> {
        let tag = tag as FT_ULong;

        unsafe {
            // Get the length
            let mut len = 0;
            if !FT_Load_Sfnt_Table(self.face, tag, 0, ptr::null_mut(), &mut len).succeeded() {
                return None
            }
            // Get the bytes
            let mut buf = vec![0u8; len as usize];
            if !FT_Load_Sfnt_Table(self.face, tag, 0, buf.as_mut_ptr(), &mut len).succeeded() {
                return None
            }
            Some(FontTable { buffer: buf })
        }
    }
}

impl<'a> FontHandle {
    fn set_char_size(face: FT_Face, pt_size: Au) -> Result<(), ()>{
        let char_width = float_to_fixed_ft((0.5f64 + pt_size.to_f64_px()).floor()) as FT_F26Dot6;

        unsafe {
            let result = FT_Set_Char_Size(face, char_width, 0, 0, 0);
            if result.succeeded() { Ok(()) } else { Err(()) }
        }
    }

    fn face_rec_mut(&'a self) -> &'a mut FT_FaceRec {
        unsafe {
            &mut (*self.face)
        }
    }

    fn font_units_to_au(&self, value: f64) -> Au {
        let face = self.face_rec_mut();

        // face.size is a *c_void in the bindings, presumably to avoid
        // recursive structural types
        let size: &FT_SizeRec = unsafe { mem::transmute(&(*face.size)) };
        let metrics: &FT_Size_Metrics = &(*size).metrics;

        let em_size = face.units_per_EM as f64;
        let x_scale = (metrics.x_ppem as f64) / em_size as f64;

        // If this isn't true then we're scaling one of the axes wrong
        assert!(metrics.x_ppem == metrics.y_ppem);

        Au::from_f64_px(value * x_scale)
    }
}
<commit_msg>Simplify FontHandle::new_from_template<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

extern crate freetype;

use app_units::Au;
use font::{FontHandleMethods, FontMetrics, FontTableMethods};
use font::{FontTableTag, FractionalPixel};
use freetype::freetype::{FTErrorMethods, FT_F26Dot6, FT_Face, FT_FaceRec};
use freetype::freetype::{FT_Done_Face, FT_New_Memory_Face};
use freetype::freetype::{FT_Get_Char_Index, FT_Get_Postscript_Name};
use freetype::freetype::{FT_Get_Kerning, FT_Get_Sfnt_Table, FT_Load_Sfnt_Table};
use freetype::freetype::{FT_GlyphSlot, FT_Library, FT_Long, FT_ULong};
use freetype::freetype::{FT_KERNING_DEFAULT, FT_STYLE_FLAG_BOLD, FT_STYLE_FLAG_ITALIC};
use freetype::freetype::{FT_Load_Glyph, FT_Set_Char_Size};
use freetype::freetype::{FT_SizeRec, FT_Size_Metrics, FT_UInt, struct_FT_Vector_};
use freetype::freetype::{ft_sfnt_os2};
use freetype::tt_os2::TT_OS2;
use libc::c_char;
use platform::font_context::FontContextHandle;
use platform::font_template::FontTemplateData;
use std::sync::Arc;
use std::{mem, ptr};
use style::computed_values::{font_stretch, font_weight};
use text::glyph::GlyphId;
use text::util::{fixed_to_float, float_to_fixed};
use util::str::c_str_to_string;

fn float_to_fixed_ft(f: f64) -> i32 {
    float_to_fixed(6, f)
}

fn fixed_to_float_ft(f: i32) -> f64 {
    fixed_to_float(6, f)
}

pub struct FontTable {
    buffer: Vec<u8>,
}

impl FontTableMethods for FontTable {
    fn buffer(&self) -> &[u8] {
        &self.buffer
    }
}

#[derive(Debug)]
pub struct FontHandle {
    // The font binary. This must stay valid for the lifetime of the font,
    // if the font is created using FT_Memory_Face.
    font_data: Arc<FontTemplateData>,
    face: FT_Face,
    handle: FontContextHandle,
}

impl Drop for FontHandle {
    fn drop(&mut self) {
        assert!(!self.face.is_null());
        unsafe {
            if !FT_Done_Face(self.face).succeeded() {
                panic!("FT_Done_Face failed");
            }
        }
    }
}

impl FontHandleMethods for FontHandle {
    fn new_from_template(fctx: &FontContextHandle,
                       template: Arc<FontTemplateData>,
                       pt_size: Option<Au>)
                        -> Result<FontHandle, ()> {
        let ft_ctx: FT_Library = fctx.ctx.ctx;
        if ft_ctx.is_null() { return Err(()); }

        return create_face_from_buffer(ft_ctx, &template.bytes, pt_size).map(|face| {
            let handle = FontHandle {
                  face: face,
                  font_data: template.clone(),
                  handle: fctx.clone(),
            };
            handle
        });

        fn create_face_from_buffer(lib: FT_Library, buffer: &[u8], pt_size: Option<Au>)
                                   -> Result<FT_Face, ()> {
            unsafe {
                let mut face: FT_Face = ptr::null_mut();
                let face_index = 0 as FT_Long;
                let result = FT_New_Memory_Face(lib, buffer.as_ptr(), buffer.len() as FT_Long,
                                                face_index, &mut face);

                if !result.succeeded() || face.is_null() {
                    return Err(());
                }
                if let Some(s) = pt_size {
                    try!(FontHandle::set_char_size(face, s).or(Err(())))
                }
                Ok(face)
            }
        }
    }
    fn template(&self) -> Arc<FontTemplateData> {
        self.font_data.clone()
    }
    fn family_name(&self) -> String {
        unsafe {
            c_str_to_string((*self.face).family_name as *const c_char)
        }
    }
    fn face_name(&self) -> String {
        unsafe {
            c_str_to_string(FT_Get_Postscript_Name(self.face) as *const c_char)
        }
    }
    fn is_italic(&self) -> bool {
        unsafe { (*self.face).style_flags & FT_STYLE_FLAG_ITALIC != 0 }
    }
    fn boldness(&self) -> font_weight::T {
        let default_weight = font_weight::T::Weight400;
        if unsafe { (*self.face).style_flags & FT_STYLE_FLAG_BOLD == 0 } {
            default_weight
        } else {
            unsafe {
                let os2 = FT_Get_Sfnt_Table(self.face, ft_sfnt_os2) as *mut TT_OS2;
                let valid = !os2.is_null() && (*os2).version != 0xffff;
                if valid {
                    let weight =(*os2).usWeightClass;
                    match weight {
                        1 | 100...199 => font_weight::T::Weight100,
                        2 | 200...299 => font_weight::T::Weight200,
                        3 | 300...399 => font_weight::T::Weight300,
                        4 | 400...499 => font_weight::T::Weight400,
                        5 | 500...599 => font_weight::T::Weight500,
                        6 | 600...699 => font_weight::T::Weight600,
                        7 | 700...799 => font_weight::T::Weight700,
                        8 | 800...899 => font_weight::T::Weight800,
                        9 | 900...999 => font_weight::T::Weight900,
                        _ => default_weight
                    }
                } else {
                    default_weight
                }
            }
        }
    }
    fn stretchiness(&self) -> font_stretch::T {
        // TODO(pcwalton): Implement this.
        font_stretch::T::normal
    }

    fn glyph_index(&self, codepoint: char) -> Option<GlyphId> {
        assert!(!self.face.is_null());
        unsafe {
            let idx = FT_Get_Char_Index(self.face, codepoint as FT_ULong);
            if idx != 0 as FT_UInt {
                Some(idx as GlyphId)
            } else {
                debug!("Invalid codepoint: {}", codepoint);
                None
            }
        }
    }

    fn glyph_h_kerning(&self, first_glyph: GlyphId, second_glyph: GlyphId)
                       -> FractionalPixel {
        assert!(!self.face.is_null());
        let mut delta = struct_FT_Vector_ { x: 0, y: 0 };
        unsafe {
            FT_Get_Kerning(self.face, first_glyph, second_glyph, FT_KERNING_DEFAULT, &mut delta);
        }
        fixed_to_float_ft(delta.x as i32)
    }

    fn glyph_h_advance(&self, glyph: GlyphId) -> Option<FractionalPixel> {
        assert!(!self.face.is_null());
        unsafe {
            let res =  FT_Load_Glyph(self.face, glyph as FT_UInt, 0);
            if res.succeeded() {
                let void_glyph = (*self.face).glyph;
                let slot: FT_GlyphSlot = mem::transmute(void_glyph);
                assert!(!slot.is_null());
                let advance = (*slot).metrics.horiAdvance;
                debug!("h_advance for {} is {}", glyph, advance);
                let advance = advance as i32;
                Some(fixed_to_float_ft(advance) as FractionalPixel)
            } else {
                debug!("Unable to load glyph {}. reason: {}", glyph, res);
                None
            }
        }
    }

    fn metrics(&self) -> FontMetrics {
        /* TODO(Issue #76): complete me */
        let face = self.face_rec_mut();

        let underline_size = self.font_units_to_au(face.underline_thickness as f64);
        let underline_offset = self.font_units_to_au(face.underline_position as f64);
        let em_size = self.font_units_to_au(face.units_per_EM as f64);
        let ascent = self.font_units_to_au(face.ascender as f64);
        let descent = self.font_units_to_au(face.descender as f64);
        let max_advance = self.font_units_to_au(face.max_advance_width as f64);

        // 'leading' is supposed to be the vertical distance between two baselines,
        // reflected by the height attribute in freetype.  On OS X (w/ CTFont),
        // leading represents the distance between the bottom of a line descent to
        // the top of the next line's ascent or: (line_height - ascent - descent),
        // see http://stackoverflow.com/a/5635981 for CTFont implementation.
        // Convert using a formula similar to what CTFont returns for consistency.
        let height = self.font_units_to_au(face.height as f64);
        let leading = height - (ascent + descent);

        let mut strikeout_size = Au(0);
        let mut strikeout_offset = Au(0);
        let mut x_height = Au(0);
        unsafe {
            let os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2) as *mut TT_OS2;
            let valid = !os2.is_null() && (*os2).version != 0xffff;
            if valid {
               strikeout_size = self.font_units_to_au((*os2).yStrikeoutSize as f64);
               strikeout_offset = self.font_units_to_au((*os2).yStrikeoutPosition as f64);
               x_height = self.font_units_to_au((*os2).sxHeight as f64);
            }
        }

        let average_advance = self.glyph_index('0')
                                  .and_then(|idx| self.glyph_h_advance(idx))
                                  .map_or(max_advance, |advance| self.font_units_to_au(advance));

        let metrics = FontMetrics {
            underline_size:   underline_size,
            underline_offset: underline_offset,
            strikeout_size:   strikeout_size,
            strikeout_offset: strikeout_offset,
            leading:          leading,
            x_height:         x_height,
            em_size:          em_size,
            ascent:           ascent,
            descent:          -descent, // linux font's seem to use the opposite sign from mac
            max_advance:      max_advance,
            average_advance:  average_advance,
            line_gap:         height,
        };

        debug!("Font metrics (@{}px): {:?}", em_size.to_f32_px(), metrics);
        metrics
    }

    fn table_for_tag(&self, tag: FontTableTag) -> Option<FontTable> {
        let tag = tag as FT_ULong;

        unsafe {
            // Get the length
            let mut len = 0;
            if !FT_Load_Sfnt_Table(self.face, tag, 0, ptr::null_mut(), &mut len).succeeded() {
                return None
            }
            // Get the bytes
            let mut buf = vec![0u8; len as usize];
            if !FT_Load_Sfnt_Table(self.face, tag, 0, buf.as_mut_ptr(), &mut len).succeeded() {
                return None
            }
            Some(FontTable { buffer: buf })
        }
    }
}

impl<'a> FontHandle {
    fn set_char_size(face: FT_Face, pt_size: Au) -> Result<(), ()>{
        let char_width = float_to_fixed_ft((0.5f64 + pt_size.to_f64_px()).floor()) as FT_F26Dot6;

        unsafe {
            let result = FT_Set_Char_Size(face, char_width, 0, 0, 0);
            if result.succeeded() { Ok(()) } else { Err(()) }
        }
    }

    fn face_rec_mut(&'a self) -> &'a mut FT_FaceRec {
        unsafe {
            &mut (*self.face)
        }
    }

    fn font_units_to_au(&self, value: f64) -> Au {
        let face = self.face_rec_mut();

        // face.size is a *c_void in the bindings, presumably to avoid
        // recursive structural types
        let size: &FT_SizeRec = unsafe { mem::transmute(&(*face.size)) };
        let metrics: &FT_Size_Metrics = &(*size).metrics;

        let em_size = face.units_per_EM as f64;
        let x_scale = (metrics.x_ppem as f64) / em_size as f64;

        // If this isn't true then we're scaling one of the axes wrong
        assert!(metrics.x_ppem == metrics.y_ppem);

        Au::from_f64_px(value * x_scale)
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016-2017 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::str::FromStr;
use std::string::ToString;
use std::collections::{BTreeMap, HashMap};

use hcore::package::{PackageIdent, Identifiable};
use hcore::fs;
use manager::service::config::{ServiceConfig, Svc};
use handlebars::{Handlebars, Helper, Renderable, RenderContext, RenderError, Context};
use serde_json;
use toml;

type RenderResult = Result<(), RenderError>;

pub fn each_alive(h: &Helper, r: &Handlebars, rc: &mut RenderContext) -> RenderResult {
    let value = try!(h.param(0)
            .ok_or_else(|| RenderError::new("Param not found for helper \"eachAlive\"")))
        .value();

    let template = try!(h.template()
        .ok_or_else(|| RenderError::new("No content to render inside the helper \"eachAlive\"")));
    let default_array = Vec::default();
    let value_array = value.as_array().unwrap_or(&default_array);
    for i in 0..value_array.len() {
        let member = try!(value_array[i]
            .as_object()
            .ok_or_else(|| {
                RenderError::new(format!("Param value is not a valid census member.  Parameter \
                                          content is: {:?}",
                                         value_array[i]))
            }));
        if member["alive"].as_bool().unwrap_or(false) {
            debug!("Alive! {:?}", value_array[i]);
            let mut map = HashMap::default();
            let mut local_context = Context::wraps(&value_array[i]);
            let mut writer = rc.writer();
            let mut local_rc = RenderContext::new(&mut local_context, &mut map, &mut writer);
            try!(template.render(r, &mut local_rc));
        } else {
            debug!("Dead! {:?}", value_array[i]);
        }
    }
    Ok(())
}

pub fn pkg_path_for(h: &Helper, _: &Handlebars, rc: &mut RenderContext) -> RenderResult {
    let param = try!(h.param(0)
        .and_then(|v| v.value().as_str())
        .ok_or_else(|| RenderError::new("Expected a string parameter for \"pkgPathFor\"")));
    let param = try!(PackageIdent::from_str(param).map_err(|e| {
            RenderError::new(format!("Bad package identifier for \"pkgPathFor\", {}", e))
        }));
    let cfg = try!(serde_json::from_value::<ServiceConfig>(rc.context().data().clone())
        .map_err(|_| {
            RenderError::new("\"pkgPathFor\" can only be used on a template bound to a service \
                              config.")
        }));
    let pkg = cfg.pkg
        .deps
        .iter()
        .find(|ident| ident.satisfies(&param))
        .and_then(|i| Some(fs::pkg_install_path(&i, None).to_string_lossy().into_owned()))
        .unwrap_or("".to_string());
    try!(rc.writer.write(pkg.into_bytes().as_ref()));
    Ok(())
}

pub fn to_uppercase(h: &Helper, _: &Handlebars, rc: &mut RenderContext) -> RenderResult {
    let param = try!(h.param(0)
        .and_then(|v| v.value().as_str())
        .ok_or_else(|| RenderError::new("Expected a string parameter for \"toUppercase\"")));
    try!(rc.writer.write(param.to_uppercase().into_bytes().as_ref()));
    Ok(())
}

pub fn to_lowercase(h: &Helper, _: &Handlebars, rc: &mut RenderContext) -> RenderResult {
    let param = try!(h.param(0)
        .and_then(|v| v.value().as_str())
        .ok_or_else(|| RenderError::new("Expected a string parameter for \"toLowercase\"")));
    try!(rc.writer.write(param.to_lowercase().into_bytes().as_ref()));
    Ok(())
}

pub fn str_replace(h: &Helper, _: &Handlebars, rc: &mut RenderContext) -> RenderResult {
    let param = try!(h.param(0)
        .and_then(|v| v.value().as_str())
        .ok_or_else(|| RenderError::new("Expected 3 string parameters for \"strReplace\"")));
    let old = try!(h.param(1)
        .and_then(|v| v.value().as_str())
        .ok_or_else(|| RenderError::new("Expected 3 string parameters for \"strReplace\"")));
    let new = try!(h.param(2)
        .and_then(|v| v.value().as_str())
        .ok_or_else(|| RenderError::new("Expected 3 string parameters for \"strReplace\"")));
    try!(rc.writer.write(param.replace(old, new).into_bytes().as_ref()));
    Ok(())
}

pub fn to_json(h: &Helper, _: &Handlebars, rc: &mut RenderContext) -> RenderResult {
    let param = try!(h.param(0)
            .ok_or_else(|| RenderError::new("Expected 1 parameter for \"toJson\"")))
        .value();
    let json = try!(serde_json::to_string_pretty(param)
        .map_err(|e| RenderError::new(format!("Can't serialize parameter to JSON: {}", e))));
    try!(rc.writer.write(json.into_bytes().as_ref()));
    Ok(())
}

pub fn to_toml(h: &Helper, _: &Handlebars, rc: &mut RenderContext) -> RenderResult {
    let param = try!(h.param(0)
            .ok_or_else(|| RenderError::new("Expected 1 parameter for \"toToml\"")))
        .value();
    let bytes = try!(toml::ser::to_vec(&param)
        .map_err(|e| RenderError::new(format!("Can't serialize parameter to TOML: {}", e))));
    try!(rc.writer.write_all(bytes.as_ref()));
    Ok(())
}
<commit_msg>clean up unused imports to templating/helpers.rs<commit_after>// Copyright (c) 2016-2017 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::str::FromStr;
use std::string::ToString;
use std::collections::HashMap;

use hcore::package::{PackageIdent, Identifiable};
use hcore::fs;
use manager::service::config::ServiceConfig;
use handlebars::{Handlebars, Helper, Renderable, RenderContext, RenderError, Context};
use serde_json;
use toml;

type RenderResult = Result<(), RenderError>;

pub fn each_alive(h: &Helper, r: &Handlebars, rc: &mut RenderContext) -> RenderResult {
    let value = try!(h.param(0)
            .ok_or_else(|| RenderError::new("Param not found for helper \"eachAlive\"")))
        .value();

    let template = try!(h.template()
        .ok_or_else(|| RenderError::new("No content to render inside the helper \"eachAlive\"")));
    let default_array = Vec::default();
    let value_array = value.as_array().unwrap_or(&default_array);
    for i in 0..value_array.len() {
        let member = try!(value_array[i]
            .as_object()
            .ok_or_else(|| {
                RenderError::new(format!("Param value is not a valid census member.  Parameter \
                                          content is: {:?}",
                                         value_array[i]))
            }));
        if member["alive"].as_bool().unwrap_or(false) {
            debug!("Alive! {:?}", value_array[i]);
            let mut map = HashMap::default();
            let mut local_context = Context::wraps(&value_array[i]);
            let mut writer = rc.writer();
            let mut local_rc = RenderContext::new(&mut local_context, &mut map, &mut writer);
            try!(template.render(r, &mut local_rc));
        } else {
            debug!("Dead! {:?}", value_array[i]);
        }
    }
    Ok(())
}

pub fn pkg_path_for(h: &Helper, _: &Handlebars, rc: &mut RenderContext) -> RenderResult {
    let param = try!(h.param(0)
        .and_then(|v| v.value().as_str())
        .ok_or_else(|| RenderError::new("Expected a string parameter for \"pkgPathFor\"")));
    let param = try!(PackageIdent::from_str(param).map_err(|e| {
            RenderError::new(format!("Bad package identifier for \"pkgPathFor\", {}", e))
        }));
    let cfg = try!(serde_json::from_value::<ServiceConfig>(rc.context().data().clone())
        .map_err(|_| {
            RenderError::new("\"pkgPathFor\" can only be used on a template bound to a service \
                              config.")
        }));
    let pkg = cfg.pkg
        .deps
        .iter()
        .find(|ident| ident.satisfies(&param))
        .and_then(|i| Some(fs::pkg_install_path(&i, None).to_string_lossy().into_owned()))
        .unwrap_or("".to_string());
    try!(rc.writer.write(pkg.into_bytes().as_ref()));
    Ok(())
}

pub fn to_uppercase(h: &Helper, _: &Handlebars, rc: &mut RenderContext) -> RenderResult {
    let param = try!(h.param(0)
        .and_then(|v| v.value().as_str())
        .ok_or_else(|| RenderError::new("Expected a string parameter for \"toUppercase\"")));
    try!(rc.writer.write(param.to_uppercase().into_bytes().as_ref()));
    Ok(())
}

pub fn to_lowercase(h: &Helper, _: &Handlebars, rc: &mut RenderContext) -> RenderResult {
    let param = try!(h.param(0)
        .and_then(|v| v.value().as_str())
        .ok_or_else(|| RenderError::new("Expected a string parameter for \"toLowercase\"")));
    try!(rc.writer.write(param.to_lowercase().into_bytes().as_ref()));
    Ok(())
}

pub fn str_replace(h: &Helper, _: &Handlebars, rc: &mut RenderContext) -> RenderResult {
    let param = try!(h.param(0)
        .and_then(|v| v.value().as_str())
        .ok_or_else(|| RenderError::new("Expected 3 string parameters for \"strReplace\"")));
    let old = try!(h.param(1)
        .and_then(|v| v.value().as_str())
        .ok_or_else(|| RenderError::new("Expected 3 string parameters for \"strReplace\"")));
    let new = try!(h.param(2)
        .and_then(|v| v.value().as_str())
        .ok_or_else(|| RenderError::new("Expected 3 string parameters for \"strReplace\"")));
    try!(rc.writer.write(param.replace(old, new).into_bytes().as_ref()));
    Ok(())
}

pub fn to_json(h: &Helper, _: &Handlebars, rc: &mut RenderContext) -> RenderResult {
    let param = try!(h.param(0)
            .ok_or_else(|| RenderError::new("Expected 1 parameter for \"toJson\"")))
        .value();
    let json = try!(serde_json::to_string_pretty(param)
        .map_err(|e| RenderError::new(format!("Can't serialize parameter to JSON: {}", e))));
    try!(rc.writer.write(json.into_bytes().as_ref()));
    Ok(())
}

pub fn to_toml(h: &Helper, _: &Handlebars, rc: &mut RenderContext) -> RenderResult {
    let param = try!(h.param(0)
            .ok_or_else(|| RenderError::new("Expected 1 parameter for \"toToml\"")))
        .value();
    let bytes = try!(toml::ser::to_vec(&param)
        .map_err(|e| RenderError::new(format!("Can't serialize parameter to TOML: {}", e))));
    try!(rc.writer.write_all(bytes.as_ref()));
    Ok(())
}
<|endoftext|>


<commit_before>#[doc="Text layout."]

import geom::size::Size2D;
import gfx::geometry::au;
import layout::base::*;     // FIXME: Can't get around import *; resolve bug.
import servo_text::text_run::text_run;
import servo_text::font::create_test_font;

class text_box {
    let text: str;
    let mut run: option<text_run>;

    new(-text: str) {
        self.text = text;
        self.run = none;
    }
}

#[doc="The main reflow routine for text layout."]
impl text_layout_methods for @Box {
    fn reflow_text(_available_width: au, subbox: @text_box) {
        alt self.kind {
            TextBox(*) { /* ok */ }
            _ { fail "expected text box in reflow_text!" }
        };

        let font = create_test_font();
        let run = text_run(&font, subbox.text);
        subbox.run = some(run);

        self.bounds.size =
            Size2D(alt vec::last_opt(run.glyphs) {
                        some(glyph) {
                            au(*glyph.pos.offset.x + *glyph.pos.advance.x)
                        }
                        none {
                            au(0)
                        }
                   },
                   au(60 * 14));
    }
}

<commit_msg>Calculate the size of the text_box from the text_run<commit_after>#[doc="Text layout."]

import geom::size::Size2D;
import gfx::geometry::au;
import layout::base::*;     // FIXME: Can't get around import *; resolve bug.
import servo_text::text_run::text_run;
import servo_text::font::create_test_font;

class text_box {
    let text: str;
    let mut run: option<text_run>;

    new(-text: str) {
        self.text = text;
        self.run = none;
    }
}

#[doc="The main reflow routine for text layout."]
impl text_layout_methods for @Box {
    fn reflow_text(_available_width: au, subbox: @text_box) {
        alt self.kind {
            TextBox(*) { /* ok */ }
            _ { fail "expected text box in reflow_text!" }
        };

        let font = create_test_font();
        let run = text_run(&font, subbox.text);
        subbox.run = some(run);
        self.bounds.size = run.size();
    }
}

fn should_calculate_the_size_of_the_text_box() {
    #[test];

    import dom::rcu::{Scope};
    import dom::base::{Text, NodeScope};
    import box_builder::box_builder_methods;
    import util::tree;
    import gfx::geometry::px_to_au;

    let s = Scope();
    let n = s.new_node(Text("firecracker"));
    let b = n.construct_boxes();

    let subbox = alt check b.kind { TextBox(subbox) { subbox } };
    b.reflow_text(px_to_au(800), subbox);
    let expected = Size2D(px_to_au(110), px_to_au(14));
    assert b.bounds.size == Size2D(px_to_au(110), px_to_au(14));
}
<|endoftext|>