<commit_before>use std::fs::File;
use std::io::{Result, Write};
use std::path::Path;

use super::Object::*;
use super::{Dictionary, Document, Object, Stream, StringFormat};
use crate::xref::*;

impl Document {
	/// Save PDF document to specified file path.
	#[inline]
	pub fn save<P: AsRef<Path>>(&mut self, path: P) -> Result<File> {
		let mut file = File::create(path)?;
		self.save_internal(&mut file)?;
		Ok(file)
	}

	/// Save PDF to arbitrary target
	#[inline]
	pub fn save_to<W: Write>(&mut self, target: &mut W) -> Result<()> {
		self.save_internal(target)
	}

	fn save_internal<W: Write>(&mut self, target: &mut W) -> Result<()> {
		let mut target = CountingWrite { inner: target, bytes_written: 0 };
		let mut xref = Xref::new(self.max_id + 1);
		target.write_all(format!("%PDF-{}\n", self.version).as_bytes())?;

		for (&(id, generation), object) in &self.objects {
			if object.type_name().map(|name| ["ObjStm", "XRef", "Linearized"].contains(&name)) != Some(true) {
				Writer::write_indirect_object(&mut target, id, generation, object, &mut xref)?;
			}
		}

		let xref_start = target.bytes_written;
		Writer::write_xref(&mut target, &xref)?;
		self.write_trailer(&mut target)?;
		target.write_all(format!("\nstartxref\n{}\n%%EOF", xref_start).as_bytes())?;

		Ok(())
	}

	fn write_trailer(&mut self, file: &mut Write) -> Result<()> {
		self.trailer.set("Size", i64::from(self.max_id + 1));
		file.write_all(b"trailer\n")?;
		Writer::write_dictionary(file, &self.trailer)?;
		Ok(())
	}
}

pub struct Writer;

impl Writer {
	fn need_separator(object: &Object) -> bool {
		match *object {
			Null => true,
			Boolean(_) => true,
			Integer(_) => true,
			Real(_) => true,
			Reference(_) => true,
			_ => false,
		}
	}

	fn need_end_separator(object: &Object) -> bool {
		match *object {
			Null => true,
			Boolean(_) => true,
			Integer(_) => true,
			Real(_) => true,
			Name(_) => true,
			Reference(_) => true,
			Object::Stream(_) => true,
			_ => false,
		}
	}

	fn write_xref(file: &mut Write, xref: &Xref) -> Result<()> {
		file.write_all(b"xref\n")?;
		file.write_all(format!("0 {}\n", xref.size).as_bytes())?;

		let mut write_xref_entry = |offset: u32, generation: u16, kind: char| file.write_all(format!("{:>010} {:>05} {} \n", offset, generation, kind).as_bytes());
		write_xref_entry(0, 65535, 'f')?;

		let mut obj_id = 1;
		while obj_id < xref.size {
			if let Some(entry) = xref.get(obj_id) {
				if let XrefEntry::Normal { offset, generation } = *entry {
					write_xref_entry(offset, generation, 'n')?;
				};
			} else {
				write_xref_entry(0, 65535, 'f')?;
			}
			obj_id += 1;
		}
		Ok(())
	}

	fn write_indirect_object<'a, W: Write>(file: &mut CountingWrite<&mut W>, id: u32, generation: u16, object: &'a Object, xref: &mut Xref) -> Result<()> {
		let offset = file.bytes_written as u32;
		xref.insert(id, XrefEntry::Normal { offset, generation });
		file.write_all(format!("{} {} obj{}", id, generation, if Writer::need_separator(object) { " " } else { "" }).as_bytes())?;
		Writer::write_object(file, object)?;
		file.write_all(format!("{}endobj\n", if Writer::need_end_separator(object) { " " } else { "" }).as_bytes())?;
		Ok(())
	}

	pub fn write_object<'a>(file: &mut Write, object: &'a Object) -> Result<()> {
		match *object {
			Null => file.write_all(b"null"),
			Boolean(ref value) => if *value {
				file.write_all(b"true")
			} else {
				file.write_all(b"false")
			},
			Integer(ref value) => {
				let _ = itoa::write(file, *value);
				Ok(())
			}
			Real(ref value) => {
				let _ = dtoa::write(file, *value);
				Ok(())
			}
			Name(ref name) => Writer::write_name(file, name),
			String(ref text, ref format) => Writer::write_string(file, text, format),
			Array(ref array) => Writer::write_array(file, array),
			Object::Dictionary(ref dict) => Writer::write_dictionary(file, dict),
			Object::Stream(ref stream) => Writer::write_stream(file, stream),
			Reference(ref id) => file.write_all(format!("{} {} R", id.0, id.1).as_bytes()),
		}
	}

	fn write_name<'a>(file: &mut Write, name: &'a [u8]) -> Result<()> {
		file.write_all(b"/")?;
		for &byte in name {
			// white-space and delimiter chars are encoded to # sequences
			// also encode bytes outside of the range 33 (!) to 126 (~)
			if b" \t\n\r\x0C()<>[]{}/%#".contains(&byte) || byte < 33 || byte > 126 {
				file.write_all(format!("#{:02X}", byte).as_bytes())?;
			} else {
				file.write_all(&[byte])?;
			}
		}
		Ok(())
	}

	fn write_string<'a>(file: &mut Write, text: &'a [u8], format: &'a StringFormat) -> Result<()> {
		match *format {
			// Within a Literal string, backslash (\) and unbalanced parentheses should be escaped.
			// This rule apply to each individual byte in a string object,
			// whether the string is interpreted as single-byte or multiple-byte character codes.
			// If an end-of-line marker appears within a literal string without a preceding backslash, the result is equivalent to \n.
			// So \r also need be escaped.
			StringFormat::Literal => {
				let mut escape_indice = Vec::new();
				let mut parentheses = Vec::new();
				for (index, &byte) in text.iter().enumerate() {
					match byte {
						b'(' => parentheses.push(index),
						b')' => {
							if !parentheses.is_empty() {
								parentheses.pop();
							} else {
								escape_indice.push(index);
							}
						}
						b'\\' | b'\r' => escape_indice.push(index),
						_ => continue,
					}
				}
				escape_indice.append(&mut parentheses);

				file.write_all(b"(")?;
				if !escape_indice.is_empty() {
					for (index, &byte) in text.iter().enumerate() {
						if escape_indice.contains(&index) {
							file.write_all(b"\\")?;
							file.write_all(&[if byte == b'\r' { b'r' } else { byte }])?;
						} else {
							file.write_all(&[byte])?;
						}
					}
				} else {
					file.write_all(text)?;
				}
				file.write_all(b")")?;
			}
			StringFormat::Hexadecimal => {
				file.write_all(b"<")?;
				for &byte in text {
					file.write_all(format!("{:02X}", byte).as_bytes())?;
				}
				file.write_all(b">")?;
			}
		}
		Ok(())
	}

	fn write_array<'a>(file: &mut Write, array: &'a [Object]) -> Result<()> {
		file.write_all(b"[")?;
		let mut first = true;
		for object in array {
			if first {
				first = false;
			} else if Writer::need_separator(object) {
				file.write_all(b" ")?;
			}
			Writer::write_object(file, object)?;
		}
		file.write_all(b"]")?;
		Ok(())
	}

	fn write_dictionary<'a>(file: &mut Write, dictionary: &'a Dictionary) -> Result<()> {
		file.write_all(b"<<")?;
		for (key, value) in dictionary {
			Writer::write_name(file, key)?;
			if Writer::need_separator(value) {
				file.write_all(b" ")?;
			}
			Writer::write_object(file, value)?;
		}
		file.write_all(b">>")?;
		Ok(())
	}

	fn write_stream<'a>(file: &mut Write, stream: &'a Stream) -> Result<()> {
		Writer::write_dictionary(file, &stream.dict)?;
		file.write_all(b"stream\n")?;
		file.write_all(&stream.content)?;
		file.write_all(b"endstream")?;
		Ok(())
	}
}

pub struct CountingWrite<W: Write> {
	inner: W,
	bytes_written: usize,
}

impl<W: Write> Write for CountingWrite<W> {
	#[inline]
	fn write(&mut self, buffer: &[u8]) -> Result<usize> {
		let result = self.inner.write(buffer);
		if let Ok(bytes) = result {
			self.bytes_written += bytes;
		}
		result
	}

	#[inline]
	fn write_all(&mut self, buffer: &[u8]) -> Result<()> {
		self.bytes_written += buffer.len();
		// If this returns `Err` we can’t know how many bytes were actually written (if any)
		// but that doesn’t matter since we’re gonna abort the entire PDF generation anyway.
		self.inner.write_all(buffer)
	}

	#[inline]
	fn flush(&mut self) -> Result<()> {
		self.inner.flush()
	}
}

#[test]
fn save_document() {
	let mut doc = Document::with_version("1.5");
	doc.objects.insert((1, 0), Null);
	doc.objects.insert((2, 0), Boolean(true));
	doc.objects.insert((3, 0), Integer(3));
	doc.objects.insert((4, 0), Real(0.5));
	doc.objects.insert((5, 0), String("text((\r)".as_bytes().to_vec(), StringFormat::Literal));
	doc.objects.insert((6, 0), String("text((\r)".as_bytes().to_vec(), StringFormat::Hexadecimal));
	doc.objects.insert((7, 0), Name(b"name \t".to_vec()));
	doc.objects.insert((8, 0), Reference((1, 0)));
	doc.objects.insert((9, 2), Array(vec![Integer(1), Integer(2), Integer(3)]));
	doc.objects.insert((11, 0), Stream(Stream::new(Dictionary::new(), vec![0x41, 0x42, 0x43])));
	let mut dict = Dictionary::new();
	dict.set("A", Null);
	dict.set("B", false);
	dict.set("C", Name(b"name".to_vec()));
	doc.objects.insert((12, 0), Object::Dictionary(dict));
	doc.max_id = 12;

	doc.save("test_0_save.pdf").unwrap();
}
<commit_msg>Be explicit about trait objects.<commit_after>use std::fs::File;
use std::io::{Result, Write};
use std::path::Path;

use super::Object::*;
use super::{Dictionary, Document, Object, Stream, StringFormat};
use crate::xref::*;

impl Document {
	/// Save PDF document to specified file path.
	#[inline]
	pub fn save<P: AsRef<Path>>(&mut self, path: P) -> Result<File> {
		let mut file = File::create(path)?;
		self.save_internal(&mut file)?;
		Ok(file)
	}

	/// Save PDF to arbitrary target
	#[inline]
	pub fn save_to<W: Write>(&mut self, target: &mut W) -> Result<()> {
		self.save_internal(target)
	}

	fn save_internal<W: Write>(&mut self, target: &mut W) -> Result<()> {
		let mut target = CountingWrite { inner: target, bytes_written: 0 };
		let mut xref = Xref::new(self.max_id + 1);
		target.write_all(format!("%PDF-{}\n", self.version).as_bytes())?;

		for (&(id, generation), object) in &self.objects {
			if object.type_name().map(|name| ["ObjStm", "XRef", "Linearized"].contains(&name)) != Some(true) {
				Writer::write_indirect_object(&mut target, id, generation, object, &mut xref)?;
			}
		}

		let xref_start = target.bytes_written;
		Writer::write_xref(&mut target, &xref)?;
		self.write_trailer(&mut target)?;
		target.write_all(format!("\nstartxref\n{}\n%%EOF", xref_start).as_bytes())?;

		Ok(())
	}

	fn write_trailer(&mut self, file: &mut dyn Write) -> Result<()> {
		self.trailer.set("Size", i64::from(self.max_id + 1));
		file.write_all(b"trailer\n")?;
		Writer::write_dictionary(file, &self.trailer)?;
		Ok(())
	}
}

pub struct Writer;

impl Writer {
	fn need_separator(object: &Object) -> bool {
		match *object {
			Null => true,
			Boolean(_) => true,
			Integer(_) => true,
			Real(_) => true,
			Reference(_) => true,
			_ => false,
		}
	}

	fn need_end_separator(object: &Object) -> bool {
		match *object {
			Null => true,
			Boolean(_) => true,
			Integer(_) => true,
			Real(_) => true,
			Name(_) => true,
			Reference(_) => true,
			Object::Stream(_) => true,
			_ => false,
		}
	}

	fn write_xref(file: &mut dyn Write, xref: &Xref) -> Result<()> {
		file.write_all(b"xref\n")?;
		file.write_all(format!("0 {}\n", xref.size).as_bytes())?;

		let mut write_xref_entry = |offset: u32, generation: u16, kind: char| file.write_all(format!("{:>010} {:>05} {} \n", offset, generation, kind).as_bytes());
		write_xref_entry(0, 65535, 'f')?;

		let mut obj_id = 1;
		while obj_id < xref.size {
			if let Some(entry) = xref.get(obj_id) {
				if let XrefEntry::Normal { offset, generation } = *entry {
					write_xref_entry(offset, generation, 'n')?;
				};
			} else {
				write_xref_entry(0, 65535, 'f')?;
			}
			obj_id += 1;
		}
		Ok(())
	}

	fn write_indirect_object<'a, W: Write>(file: &mut CountingWrite<&mut W>, id: u32, generation: u16, object: &'a Object, xref: &mut Xref) -> Result<()> {
		let offset = file.bytes_written as u32;
		xref.insert(id, XrefEntry::Normal { offset, generation });
		file.write_all(format!("{} {} obj{}", id, generation, if Writer::need_separator(object) { " " } else { "" }).as_bytes())?;
		Writer::write_object(file, object)?;
		file.write_all(format!("{}endobj\n", if Writer::need_end_separator(object) { " " } else { "" }).as_bytes())?;
		Ok(())
	}

	pub fn write_object<'a>(file: &mut dyn Write, object: &'a Object) -> Result<()> {
		match *object {
			Null => file.write_all(b"null"),
			Boolean(ref value) => if *value {
				file.write_all(b"true")
			} else {
				file.write_all(b"false")
			},
			Integer(ref value) => {
				let _ = itoa::write(file, *value);
				Ok(())
			}
			Real(ref value) => {
				let _ = dtoa::write(file, *value);
				Ok(())
			}
			Name(ref name) => Writer::write_name(file, name),
			String(ref text, ref format) => Writer::write_string(file, text, format),
			Array(ref array) => Writer::write_array(file, array),
			Object::Dictionary(ref dict) => Writer::write_dictionary(file, dict),
			Object::Stream(ref stream) => Writer::write_stream(file, stream),
			Reference(ref id) => file.write_all(format!("{} {} R", id.0, id.1).as_bytes()),
		}
	}

	fn write_name<'a>(file: &mut dyn Write, name: &'a [u8]) -> Result<()> {
		file.write_all(b"/")?;
		for &byte in name {
			// white-space and delimiter chars are encoded to # sequences
			// also encode bytes outside of the range 33 (!) to 126 (~)
			if b" \t\n\r\x0C()<>[]{}/%#".contains(&byte) || byte < 33 || byte > 126 {
				file.write_all(format!("#{:02X}", byte).as_bytes())?;
			} else {
				file.write_all(&[byte])?;
			}
		}
		Ok(())
	}

	fn write_string<'a>(file: &mut dyn Write, text: &'a [u8], format: &'a StringFormat) -> Result<()> {
		match *format {
			// Within a Literal string, backslash (\) and unbalanced parentheses should be escaped.
			// This rule apply to each individual byte in a string object,
			// whether the string is interpreted as single-byte or multiple-byte character codes.
			// If an end-of-line marker appears within a literal string without a preceding backslash, the result is equivalent to \n.
			// So \r also need be escaped.
			StringFormat::Literal => {
				let mut escape_indice = Vec::new();
				let mut parentheses = Vec::new();
				for (index, &byte) in text.iter().enumerate() {
					match byte {
						b'(' => parentheses.push(index),
						b')' => {
							if !parentheses.is_empty() {
								parentheses.pop();
							} else {
								escape_indice.push(index);
							}
						}
						b'\\' | b'\r' => escape_indice.push(index),
						_ => continue,
					}
				}
				escape_indice.append(&mut parentheses);

				file.write_all(b"(")?;
				if !escape_indice.is_empty() {
					for (index, &byte) in text.iter().enumerate() {
						if escape_indice.contains(&index) {
							file.write_all(b"\\")?;
							file.write_all(&[if byte == b'\r' { b'r' } else { byte }])?;
						} else {
							file.write_all(&[byte])?;
						}
					}
				} else {
					file.write_all(text)?;
				}
				file.write_all(b")")?;
			}
			StringFormat::Hexadecimal => {
				file.write_all(b"<")?;
				for &byte in text {
					file.write_all(format!("{:02X}", byte).as_bytes())?;
				}
				file.write_all(b">")?;
			}
		}
		Ok(())
	}

	fn write_array<'a>(file: &mut dyn Write, array: &'a [Object]) -> Result<()> {
		file.write_all(b"[")?;
		let mut first = true;
		for object in array {
			if first {
				first = false;
			} else if Writer::need_separator(object) {
				file.write_all(b" ")?;
			}
			Writer::write_object(file, object)?;
		}
		file.write_all(b"]")?;
		Ok(())
	}

	fn write_dictionary<'a>(file: &mut dyn Write, dictionary: &'a Dictionary) -> Result<()> {
		file.write_all(b"<<")?;
		for (key, value) in dictionary {
			Writer::write_name(file, key)?;
			if Writer::need_separator(value) {
				file.write_all(b" ")?;
			}
			Writer::write_object(file, value)?;
		}
		file.write_all(b">>")?;
		Ok(())
	}

	fn write_stream<'a>(file: &mut dyn Write, stream: &'a Stream) -> Result<()> {
		Writer::write_dictionary(file, &stream.dict)?;
		file.write_all(b"stream\n")?;
		file.write_all(&stream.content)?;
		file.write_all(b"endstream")?;
		Ok(())
	}
}

pub struct CountingWrite<W: Write> {
	inner: W,
	bytes_written: usize,
}

impl<W: Write> Write for CountingWrite<W> {
	#[inline]
	fn write(&mut self, buffer: &[u8]) -> Result<usize> {
		let result = self.inner.write(buffer);
		if let Ok(bytes) = result {
			self.bytes_written += bytes;
		}
		result
	}

	#[inline]
	fn write_all(&mut self, buffer: &[u8]) -> Result<()> {
		self.bytes_written += buffer.len();
		// If this returns `Err` we can’t know how many bytes were actually written (if any)
		// but that doesn’t matter since we’re gonna abort the entire PDF generation anyway.
		self.inner.write_all(buffer)
	}

	#[inline]
	fn flush(&mut self) -> Result<()> {
		self.inner.flush()
	}
}

#[test]
fn save_document() {
	let mut doc = Document::with_version("1.5");
	doc.objects.insert((1, 0), Null);
	doc.objects.insert((2, 0), Boolean(true));
	doc.objects.insert((3, 0), Integer(3));
	doc.objects.insert((4, 0), Real(0.5));
	doc.objects.insert((5, 0), String("text((\r)".as_bytes().to_vec(), StringFormat::Literal));
	doc.objects.insert((6, 0), String("text((\r)".as_bytes().to_vec(), StringFormat::Hexadecimal));
	doc.objects.insert((7, 0), Name(b"name \t".to_vec()));
	doc.objects.insert((8, 0), Reference((1, 0)));
	doc.objects.insert((9, 2), Array(vec![Integer(1), Integer(2), Integer(3)]));
	doc.objects.insert((11, 0), Stream(Stream::new(Dictionary::new(), vec![0x41, 0x42, 0x43])));
	let mut dict = Dictionary::new();
	dict.set("A", Null);
	dict.set("B", false);
	dict.set("C", Name(b"name".to_vec()));
	doc.objects.insert((12, 0), Object::Dictionary(dict));
	doc.max_id = 12;

	doc.save("test_0_save.pdf").unwrap();
}
<|endoftext|>


<commit_before>//! A module to handle `Writer`

use std::io::Write;

use errors::{Error, Result};
use events::Event;

/// XML writer.
///
/// Writes XML `Event`s to a `Write` implementor.
///
/// # Examples
///
/// ```rust
/// # extern crate quick_xml;
/// # fn main() {
/// use quick_xml::{Reader, Writer};
/// use quick_xml::events::{Event, BytesEnd, BytesStart};
/// use std::io::Cursor;
///
/// let xml = r#"<this_tag k1="v1" k2="v2"><child>text</child></this_tag>"#;
/// let mut reader = Reader::from_str(xml);
/// reader.trim_text(true);
/// let mut writer = Writer::new(Cursor::new(Vec::new()));
/// let mut buf = Vec::new();
/// loop {
///     match reader.read_event(&mut buf) {
///         Ok(Event::Start(ref e)) if e.name() == b"this_tag" => {
///
///             // crates a new element ... alternatively we could reuse `e` by calling
///             // `e.into_owned()`
///             let mut elem = BytesStart::owned(b"my_elem".to_vec(), "my_elem".len());
///
///             // collect existing attributes
///             elem.extend_attributes(e.attributes().map(|attr| attr.unwrap()));
///
///             // copy existing attributes, adds a new my-key="some value" attribute
///             elem.push_attribute(("my-key", "some value"));
///
///             // writes the event to the writer
///             assert!(writer.write_event(Event::Start(elem)).is_ok());
///         },
///         Ok(Event::End(ref e)) if e.name() == b"this_tag" => {
///             assert!(writer.write_event(Event::End(BytesEnd::borrowed(b"my_elem"))).is_ok());
///         },
///         Ok(Event::Eof) => break,
///         // we can either move or borrow the event to write, depending on your use-case
///         Ok(e) => assert!(writer.write_event(&e).is_ok()),
///         Err(e) => panic!("{}", e),
///     }
///     buf.clear();
/// }
///
/// let result = writer.into_inner().into_inner();
/// let expected = r#"<my_elem k1="v1" k2="v2" my-key="some value"><child>text</child></my_elem>"#;
/// assert_eq!(result, expected.as_bytes());
/// # }
/// ```
#[derive(Clone)]
pub struct Writer<W: Write> {
    /// underlying writer
    writer: W,
    indent: Option<Indentation>,
}

impl<W: Write> Writer<W> {
    /// Creates a Writer from a generic Write
    pub fn new(inner: W) -> Writer<W> {
        Writer {
            writer: inner,
            indent: None,
        }
    }

    /// Creates a Writer with configured whitespace indents from a generic Write
    pub fn new_with_indent(inner: W, indent_char: u8, indent_size: usize) -> Writer<W> {
        Writer {
            writer: inner,
            indent: Some(Indentation::new(indent_char, indent_size)),
        }
    }

    /// Consumes this `Writer`, returning the underlying writer.
    pub fn into_inner(self) -> W {
        self.writer
    }

    /// Get inner writer, keeping ownership
    pub fn inner(&mut self) -> &mut W {
        &mut self.writer
    }

    /// Writes the given event to the underlying writer.
    pub fn write_event<'a, E: AsRef<Event<'a>>>(&mut self, event: E) -> Result<usize> {
        let mut next_should_line_break = true;
        let result = match *event.as_ref() {
            Event::Start(ref e) => {
                let result = self.write_wrapped(b"<", e, b">");
                if let Some(i) = self.indent.as_mut() {
                    i.grow();
                }
                result
            }
            Event::End(ref e) => {
                if let Some(i) = self.indent.as_mut() {
                    i.shrink();
                }
                self.write_wrapped(b"</", e, b">")
            }
            Event::Empty(ref e) => self.write_wrapped(b"<", e, b"/>"),
            Event::Text(ref e) => {
                next_should_line_break = false;
                self.write(&e.escaped())
            }
            Event::Comment(ref e) => self.write_wrapped(b"<!--", e, b"-->"),
            Event::CData(ref e) => self.write_wrapped(b"<![CDATA[", e, b"]]>"),
            Event::Decl(ref e) => self.write_wrapped(b"<?", e, b"?>"),
            Event::PI(ref e) => self.write_wrapped(b"<?", e, b"?>"),
            Event::DocType(ref e) => self.write_wrapped(b"<!DOCTYPE", e, b">"),
            Event::Eof => Ok(0),
        };
        if let Some(i) = self.indent.as_mut() {
            i.should_line_break = next_should_line_break;
        }
        result
    }

    /// Writes bytes
    #[inline]
    pub fn write(&mut self, value: &[u8]) -> Result<usize> {
        self.writer.write(value).map_err(Error::Io)
    }

    #[inline]
    fn write_wrapped(&mut self, before: &[u8], value: &[u8], after: &[u8]) -> Result<usize> {
        let mut wrote = 0;
        if let Some(ref i) = self.indent {
            if i.should_line_break {
                wrote = self.writer.write(b"\n").map_err(Error::Io)?
                    + self
                        .writer
                        .write(&i.indents[..i.indents_len])
                        .map_err(Error::Io)?;
            }
        }
        Ok(wrote + self.write(before)? + self.write(value)? + self.write(after)?)
    }
}

#[derive(Clone)]
struct Indentation {
    should_line_break: bool,
    indent_char: u8,
    indent_size: usize,
    indents: Vec<u8>,
    indents_len: usize,
}

impl Indentation {
    fn new(indent_char: u8, indent_size: usize) -> Indentation {
        Indentation {
            should_line_break: false,
            indent_char,
            indent_size,
            indents: vec![indent_char; 128],
            indents_len: 0,
        }
    }

    fn grow(&mut self) {
        self.indents_len = self.indents_len + self.indent_size;
        if self.indents_len > self.indents.len() {
            self.indents.resize(self.indents_len, self.indent_char);
        }
    }

    fn shrink(&mut self) {
        self.indents_len = self.indents_len - self.indent_size;
    }
}
<commit_msg>Add write_indent method to Writer to enable manually writing a newline and indentation in cases where the `next_should_line_break` heuristic fails<commit_after>//! A module to handle `Writer`

use std::io::Write;

use errors::{Error, Result};
use events::Event;

/// XML writer.
///
/// Writes XML `Event`s to a `Write` implementor.
///
/// # Examples
///
/// ```rust
/// # extern crate quick_xml;
/// # fn main() {
/// use quick_xml::{Reader, Writer};
/// use quick_xml::events::{Event, BytesEnd, BytesStart};
/// use std::io::Cursor;
///
/// let xml = r#"<this_tag k1="v1" k2="v2"><child>text</child></this_tag>"#;
/// let mut reader = Reader::from_str(xml);
/// reader.trim_text(true);
/// let mut writer = Writer::new(Cursor::new(Vec::new()));
/// let mut buf = Vec::new();
/// loop {
///     match reader.read_event(&mut buf) {
///         Ok(Event::Start(ref e)) if e.name() == b"this_tag" => {
///
///             // crates a new element ... alternatively we could reuse `e` by calling
///             // `e.into_owned()`
///             let mut elem = BytesStart::owned(b"my_elem".to_vec(), "my_elem".len());
///
///             // collect existing attributes
///             elem.extend_attributes(e.attributes().map(|attr| attr.unwrap()));
///
///             // copy existing attributes, adds a new my-key="some value" attribute
///             elem.push_attribute(("my-key", "some value"));
///
///             // writes the event to the writer
///             assert!(writer.write_event(Event::Start(elem)).is_ok());
///         },
///         Ok(Event::End(ref e)) if e.name() == b"this_tag" => {
///             assert!(writer.write_event(Event::End(BytesEnd::borrowed(b"my_elem"))).is_ok());
///         },
///         Ok(Event::Eof) => break,
///         // we can either move or borrow the event to write, depending on your use-case
///         Ok(e) => assert!(writer.write_event(&e).is_ok()),
///         Err(e) => panic!("{}", e),
///     }
///     buf.clear();
/// }
///
/// let result = writer.into_inner().into_inner();
/// let expected = r#"<my_elem k1="v1" k2="v2" my-key="some value"><child>text</child></my_elem>"#;
/// assert_eq!(result, expected.as_bytes());
/// # }
/// ```
#[derive(Clone)]
pub struct Writer<W: Write> {
    /// underlying writer
    writer: W,
    indent: Option<Indentation>,
}

impl<W: Write> Writer<W> {
    /// Creates a Writer from a generic Write
    pub fn new(inner: W) -> Writer<W> {
        Writer {
            writer: inner,
            indent: None,
        }
    }

    /// Creates a Writer with configured whitespace indents from a generic Write
    pub fn new_with_indent(inner: W, indent_char: u8, indent_size: usize) -> Writer<W> {
        Writer {
            writer: inner,
            indent: Some(Indentation::new(indent_char, indent_size)),
        }
    }

    /// Consumes this `Writer`, returning the underlying writer.
    pub fn into_inner(self) -> W {
        self.writer
    }

    /// Get inner writer, keeping ownership
    pub fn inner(&mut self) -> &mut W {
        &mut self.writer
    }

    /// Writes the given event to the underlying writer.
    pub fn write_event<'a, E: AsRef<Event<'a>>>(&mut self, event: E) -> Result<usize> {
        let mut next_should_line_break = true;
        let result = match *event.as_ref() {
            Event::Start(ref e) => {
                let result = self.write_wrapped(b"<", e, b">");
                if let Some(i) = self.indent.as_mut() {
                    i.grow();
                }
                result
            }
            Event::End(ref e) => {
                if let Some(i) = self.indent.as_mut() {
                    i.shrink();
                }
                self.write_wrapped(b"</", e, b">")
            }
            Event::Empty(ref e) => self.write_wrapped(b"<", e, b"/>"),
            Event::Text(ref e) => {
                next_should_line_break = false;
                self.write(&e.escaped())
            }
            Event::Comment(ref e) => self.write_wrapped(b"<!--", e, b"-->"),
            Event::CData(ref e) => self.write_wrapped(b"<![CDATA[", e, b"]]>"),
            Event::Decl(ref e) => self.write_wrapped(b"<?", e, b"?>"),
            Event::PI(ref e) => self.write_wrapped(b"<?", e, b"?>"),
            Event::DocType(ref e) => self.write_wrapped(b"<!DOCTYPE", e, b">"),
            Event::Eof => Ok(0),
        };
        if let Some(i) = self.indent.as_mut() {
            i.should_line_break = next_should_line_break;
        }
        result
    }

    /// Writes bytes
    #[inline]
    pub fn write(&mut self, value: &[u8]) -> Result<usize> {
        self.writer.write(value).map_err(Error::Io)
    }

    #[inline]
    fn write_wrapped(&mut self, before: &[u8], value: &[u8], after: &[u8]) -> Result<usize> {
        let mut wrote = 0;
        if let Some(ref i) = self.indent {
            if i.should_line_break {
                wrote = self.writer.write(b"\n").map_err(Error::Io)?
                    + self
                        .writer
                        .write(&i.indents[..i.indents_len])
                        .map_err(Error::Io)?;
            }
        }
        Ok(wrote + self.write(before)? + self.write(value)? + self.write(after)?)
    }

    /// Manually write a newline and indentation at the proper level.
    ///
    /// This can be used when the heuristic to line break and indent after any [Event] apart
    /// from [Text] fails such as when a [Start] occurs directly after [Text].
    /// This method will do nothing if `Writer` was not constructed with `new_with_indent`.
    ///
    /// [Event]: events/enum.Event.html
    /// [Text]: events/enum.Event.html#variant.Text
    /// [Start]: events/enum.Event.html#variant.Start
    pub fn write_indent(&mut self) -> Result<usize> {
        let mut wrote = 0;
        if let Some(ref i) = self.indent {
            wrote = self.writer.write(b"\n").map_err(Error::Io)?
                + self
                    .writer
                    .write(&i.indents[..i.indents_len])
                    .map_err(Error::Io)?;
        }
        Ok(wrote)
    }

}

#[derive(Clone)]
struct Indentation {
    should_line_break: bool,
    indent_char: u8,
    indent_size: usize,
    indents: Vec<u8>,
    indents_len: usize,
}

impl Indentation {
    fn new(indent_char: u8, indent_size: usize) -> Indentation {
        Indentation {
            should_line_break: false,
            indent_char,
            indent_size,
            indents: vec![indent_char; 128],
            indents_len: 0,
        }
    }

    fn grow(&mut self) {
        self.indents_len = self.indents_len + self.indent_size;
        if self.indents_len > self.indents.len() {
            self.indents.resize(self.indents_len, self.indent_char);
        }
    }

    fn shrink(&mut self) {
        self.indents_len = self.indents_len - self.indent_size;
    }
}
<|endoftext|>


<commit_before>use num::{ Float, ToPrimitive, FromPrimitive };
use color::Color;
use dimensions::Dimensions;
use graphics;
use graphics::Graphics;
use graphics::character::CharacterCache;
use label;
use label::FontSize;
use mouse::Mouse;
use point::Point;
use rectangle;
use rectangle::{
    Corner
};
use ui_context::{ UIID, UiContext };
use utils::{
    clamp,
    map_range,
    val_to_string,
};
use vecmath::{
    vec2_add,
    vec2_sub,
};
use widget::Widget;

/// Represents the state of the xy_pad widget.
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum State {
    Normal,
    Highlighted,
    Clicked,
}

impl State {
    /// Return the associated Rectangle state.
    fn as_rectangle_state(&self) -> rectangle::State {
        match self {
            &State::Normal => rectangle::State::Normal,
            &State::Highlighted => rectangle::State::Highlighted,
            &State::Clicked => rectangle::State::Clicked,
        }
    }
}

widget_fns!(XYPad, State, Widget::XYPad(State::Normal));

/// Check the current state of the button.
fn get_new_state(is_over: bool,
                 prev: State,
                 mouse: Mouse) -> State {
    use mouse::ButtonState::{Down, Up};
    use self::State::{Normal, Highlighted, Clicked};
    match (is_over, prev, mouse.left) {
        (true,  Normal,  Down) => Normal,
        (true,  _,       Down) => Clicked,
        (true,  _,       Up)   => Highlighted,
        (false, Clicked, Down) => Clicked,
        _                      => Normal,
    }
}

/// Draw the crosshair.
fn draw_crosshair<B: Graphics>(
    win_w: f64,
    win_h: f64,
    graphics: &mut B,
    pos: Point,
    line_width: f64,
    vert_x: f64, hori_y: f64,
    pad_dim: Dimensions,
    color: Color
) {
    let draw_state = graphics::default_draw_state();
    let transform = graphics::abs_transform(win_w, win_h);
    let Color(col) = color;
    let line = graphics::Line::new(col, 0.5 * line_width);
    line.draw(
        [vert_x, pos[1], vert_x, pos[1] + pad_dim[1]],
        draw_state,
        transform,
        graphics
    );
    line.draw(
        [pos[0], hori_y, pos[0] + pad_dim[0], hori_y],
        draw_state,
        transform,
        graphics
    );
}

/// A context on which the builder pattern can be implemented.
pub struct XYPad<'a, X, Y, F> {
    ui_id: UIID,
    x: X, min_x: X, max_x: X,
    y: Y, min_y: Y, max_y: Y,
    line_width: f64,
    font_size: FontSize,
    pos: Point,
    dim: Dimensions,
    maybe_callback: Option<F>,
    maybe_color: Option<Color>,
    maybe_frame: Option<f64>,
    maybe_frame_color: Option<Color>,
    maybe_label: Option<&'a str>,
    maybe_label_color: Option<Color>,
    maybe_label_font_size: Option<u32>,
}

impl <'a, X, Y, F> XYPad<'a, X, Y, F> {
    #[inline]
    pub fn line_width(self, width: f64) -> XYPad<'a, X, Y, F> {
        XYPad { line_width: width, ..self }
    }
    #[inline]
    pub fn value_font_size(self, size: FontSize) -> XYPad<'a, X, Y, F> {
        XYPad { font_size: size, ..self }
    }
}

impl<'a, X, Y, F> XYPad<'a, X, Y, F> {
    /// An xy_pad builder method to be implemented by the UiContext.
    pub fn new(ui_id: UIID,
              x_val: X, min_x: X, max_x: X,
              y_val: Y, min_y: Y, max_y: Y) -> XYPad<'a, X, Y, F> {
        XYPad {
            ui_id: ui_id,
            x: x_val, min_x: min_x, max_x: max_x,
            y: y_val, min_y: min_y, max_y: max_y,
            line_width: 1.0,
            font_size: 18u32,
            pos: [0.0, 0.0],
            dim: [128.0, 128.0],
            maybe_callback: None,
            maybe_color: None,
            maybe_frame: None,
            maybe_frame_color: None,
            maybe_label: None,
            maybe_label_color: None,
            maybe_label_font_size: None,
        }
    }
}

/*
quack! {
    xy_pad: XYPad['a, X, Y, F]
    get:
        fn () -> Size [] { Size(xy_pad.dim) }
        fn () -> DefaultWidgetState [] {
            DefaultWidgetState(Widget::XYPad(State::Normal))
        }
        fn () -> Id [] { Id(xy_pad.ui_id) }
    set:
        fn (val: Color) [] { xy_pad.maybe_color = Some(val) }
        fn (val: Callback<F>) [where F: FnMut(X, Y) + 'a] {
            xy_pad.maybe_callback = Some(val.0)
        }
        fn (val: FrameColor) [] { xy_pad.maybe_frame_color = Some(val.0) }
        fn (val: FrameWidth) [] { xy_pad.maybe_frame = Some(val.0) }
        fn (val: LabelText<'a>) [] { xy_pad.maybe_label = Some(val.0) }
        fn (val: LabelColor) [] { xy_pad.maybe_label_color = Some(val.0) }
        fn (val: LabelFontSize) [] { xy_pad.maybe_label_font_size = Some(val.0) }
        fn (val: Position) [] { xy_pad.pos = val.0 }
        fn (val: Size) [] { xy_pad.dim = val.0 }
    action:
}
*/

impl<'a, X, Y, F> ::draw::Drawable for XYPad<'a, X, Y, F>
    where
        X: Float + ToPrimitive + FromPrimitive + ToString,
        Y: Float + ToPrimitive + FromPrimitive + ToString,
        F: FnMut(X, Y) + 'a
{

    fn draw<B, C>(&mut self, uic: &mut UiContext<C>, graphics: &mut B)
        where
            B: Graphics<Texture = <C as CharacterCache>::Texture>,
            C: CharacterCache
    {

        // Init.
        let state = *get_state(uic, self.ui_id);
        let mouse = uic.get_mouse_state();
        let frame_w = self.maybe_frame.unwrap_or(uic.theme.frame_width);
        let frame_w2 = frame_w * 2.0;
        let maybe_frame = match frame_w > 0.0 {
            true => Some((frame_w, self.maybe_frame_color.unwrap_or(uic.theme.frame_color))),
            false => None,
        };
        let pad_dim = vec2_sub(self.dim, [frame_w2; 2]);
        let pad_pos = vec2_add(self.pos, [frame_w, frame_w]);
        let is_over_pad = rectangle::is_over(pad_pos, mouse.pos, pad_dim);
        let new_state = get_new_state(is_over_pad, state, mouse);

        // Determine new values.
        let (new_x, new_y) = match (is_over_pad, new_state) {
            (_, State::Normal) | (_, State::Highlighted) => (self.x, self.y),
            (_, State::Clicked) => {
                let temp_x = clamp(mouse.pos[0], pad_pos[0], pad_pos[0] + pad_dim[0]);
                let temp_y = clamp(mouse.pos[1], pad_pos[1], pad_pos[1] + pad_dim[1]);
                (map_range(temp_x - self.pos[0], pad_dim[0], 0.0, self.min_x, self.max_x),
                 map_range(temp_y - self.pos[1], pad_dim[1], 0.0, self.min_y, self.max_y))
            }
        };

        // Callback if value is changed or the pad is clicked/released.
        match self.maybe_callback {
            Some(ref mut callback) => {
                if self.x != new_x || self.y != new_y { (*callback)(new_x, new_y) }
                else {
                    match (state, new_state) {
                        (State::Highlighted, State::Clicked)
                        | (State::Clicked, State::Highlighted) => (*callback)(new_x, new_y),
                        _ => (),
                    }
                }
            },
            None => (),
        }

        // Draw.
        let rect_state = new_state.as_rectangle_state();
        let color = self.maybe_color.unwrap_or(uic.theme.shape_color);
        rectangle::draw(uic.win_w, uic.win_h, graphics, rect_state, self.pos,
                        self.dim, maybe_frame, color);
        let (vert_x, hori_y) = match (is_over_pad, new_state) {
            (_, State::Normal) | (_, State::Highlighted) =>
                (pad_pos[0] + map_range(new_x, self.min_x, self.max_x, pad_dim[0], 0.0),
                 pad_pos[1] + map_range(new_y, self.min_y, self.max_y, pad_dim[1], 0.0)),
            (_, State::Clicked) =>
                (clamp(mouse.pos[0], pad_pos[0], pad_pos[0] + pad_dim[0]),
                 clamp(mouse.pos[1], pad_pos[1], pad_pos[1] + pad_dim[1])),
        };
        // Crosshair.
        draw_crosshair(uic.win_w, uic.win_h, graphics, pad_pos, self.line_width,
                       vert_x, hori_y, pad_dim, color.plain_contrast());
        // Label.
        if let Some(l_text) = self.maybe_label {
            let l_color = self.maybe_label_color.unwrap_or(uic.theme.label_color);
            let l_size = self.maybe_label_font_size.unwrap_or(uic.theme.font_size_medium);
            let l_w = label::width(uic, l_size, l_text);
            let l_x = pad_pos[0] + (pad_dim[0] - l_w) / 2.0;
            let l_y = pad_pos[1] + (pad_dim[1] - l_size as f64) / 2.0;
            let l_pos = [l_x, l_y];
            uic.draw_text(graphics, l_pos, l_size, l_color, l_text);
        }
        // xy value string.
        let x_string = val_to_string(self.x, self.max_x,
                                     self.max_x - self.min_x, self.dim[0] as usize);
        let y_string = val_to_string(self.y, self.max_y,
                                     self.max_y - self.min_y, self.dim[1] as usize);
        let xy_string = format!("{}, {}", x_string, y_string);
        let xy_string_w = label::width(uic, self.font_size, &xy_string);
        let xy_string_pos = {
            match rectangle::corner(pad_pos, [vert_x, hori_y], pad_dim) {
                Corner::TopLeft => [vert_x, hori_y],
                Corner::TopRight => [vert_x - xy_string_w, hori_y],
                Corner::BottomLeft => [vert_x, hori_y - self.font_size as f64],
                Corner::BottomRight => [vert_x - xy_string_w, hori_y - self.font_size as f64],
            }
        };
        uic.draw_text(graphics, xy_string_pos, self.font_size,
                    color.plain_contrast(), &xy_string);

        set_state(uic, self.ui_id, Widget::XYPad(new_state), self.pos, self.dim);

    }
}
<commit_msg>Implemented `Colorable` for `XYPad`<commit_after>use num::{ Float, ToPrimitive, FromPrimitive };
use color::{ Color, Colorable };
use dimensions::Dimensions;
use graphics;
use graphics::Graphics;
use graphics::character::CharacterCache;
use label;
use label::FontSize;
use mouse::Mouse;
use point::Point;
use rectangle;
use rectangle::{
    Corner
};
use ui_context::{ UIID, UiContext };
use utils::{
    clamp,
    map_range,
    val_to_string,
};
use vecmath::{
    vec2_add,
    vec2_sub,
};
use widget::Widget;

/// Represents the state of the xy_pad widget.
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum State {
    Normal,
    Highlighted,
    Clicked,
}

impl State {
    /// Return the associated Rectangle state.
    fn as_rectangle_state(&self) -> rectangle::State {
        match self {
            &State::Normal => rectangle::State::Normal,
            &State::Highlighted => rectangle::State::Highlighted,
            &State::Clicked => rectangle::State::Clicked,
        }
    }
}

widget_fns!(XYPad, State, Widget::XYPad(State::Normal));

/// Check the current state of the button.
fn get_new_state(is_over: bool,
                 prev: State,
                 mouse: Mouse) -> State {
    use mouse::ButtonState::{Down, Up};
    use self::State::{Normal, Highlighted, Clicked};
    match (is_over, prev, mouse.left) {
        (true,  Normal,  Down) => Normal,
        (true,  _,       Down) => Clicked,
        (true,  _,       Up)   => Highlighted,
        (false, Clicked, Down) => Clicked,
        _                      => Normal,
    }
}

/// Draw the crosshair.
fn draw_crosshair<B: Graphics>(
    win_w: f64,
    win_h: f64,
    graphics: &mut B,
    pos: Point,
    line_width: f64,
    vert_x: f64, hori_y: f64,
    pad_dim: Dimensions,
    color: Color
) {
    let draw_state = graphics::default_draw_state();
    let transform = graphics::abs_transform(win_w, win_h);
    let Color(col) = color;
    let line = graphics::Line::new(col, 0.5 * line_width);
    line.draw(
        [vert_x, pos[1], vert_x, pos[1] + pad_dim[1]],
        draw_state,
        transform,
        graphics
    );
    line.draw(
        [pos[0], hori_y, pos[0] + pad_dim[0], hori_y],
        draw_state,
        transform,
        graphics
    );
}

/// A context on which the builder pattern can be implemented.
pub struct XYPad<'a, X, Y, F> {
    ui_id: UIID,
    x: X, min_x: X, max_x: X,
    y: Y, min_y: Y, max_y: Y,
    line_width: f64,
    font_size: FontSize,
    pos: Point,
    dim: Dimensions,
    maybe_callback: Option<F>,
    maybe_color: Option<Color>,
    maybe_frame: Option<f64>,
    maybe_frame_color: Option<Color>,
    maybe_label: Option<&'a str>,
    maybe_label_color: Option<Color>,
    maybe_label_font_size: Option<u32>,
}

impl <'a, X, Y, F> XYPad<'a, X, Y, F> {
    #[inline]
    pub fn line_width(self, width: f64) -> XYPad<'a, X, Y, F> {
        XYPad { line_width: width, ..self }
    }
    #[inline]
    pub fn value_font_size(self, size: FontSize) -> XYPad<'a, X, Y, F> {
        XYPad { font_size: size, ..self }
    }
}

impl<'a, X, Y, F> XYPad<'a, X, Y, F> {
    /// An xy_pad builder method to be implemented by the UiContext.
    pub fn new(ui_id: UIID,
              x_val: X, min_x: X, max_x: X,
              y_val: Y, min_y: Y, max_y: Y) -> XYPad<'a, X, Y, F> {
        XYPad {
            ui_id: ui_id,
            x: x_val, min_x: min_x, max_x: max_x,
            y: y_val, min_y: min_y, max_y: max_y,
            line_width: 1.0,
            font_size: 18u32,
            pos: [0.0, 0.0],
            dim: [128.0, 128.0],
            maybe_callback: None,
            maybe_color: None,
            maybe_frame: None,
            maybe_frame_color: None,
            maybe_label: None,
            maybe_label_color: None,
            maybe_label_font_size: None,
        }
    }
}

impl<'a, X, Y, F> Colorable for XYPad<'a, X, Y, F> {
    fn color(mut self, color: Color) -> Self {
        self.maybe_color = Some(color);
        self
    }
}

/*
quack! {
    xy_pad: XYPad['a, X, Y, F]
    get:
        fn () -> Size [] { Size(xy_pad.dim) }
        fn () -> DefaultWidgetState [] {
            DefaultWidgetState(Widget::XYPad(State::Normal))
        }
        fn () -> Id [] { Id(xy_pad.ui_id) }
    set:
        fn (val: Callback<F>) [where F: FnMut(X, Y) + 'a] {
            xy_pad.maybe_callback = Some(val.0)
        }
        fn (val: FrameColor) [] { xy_pad.maybe_frame_color = Some(val.0) }
        fn (val: FrameWidth) [] { xy_pad.maybe_frame = Some(val.0) }
        fn (val: LabelText<'a>) [] { xy_pad.maybe_label = Some(val.0) }
        fn (val: LabelColor) [] { xy_pad.maybe_label_color = Some(val.0) }
        fn (val: LabelFontSize) [] { xy_pad.maybe_label_font_size = Some(val.0) }
        fn (val: Position) [] { xy_pad.pos = val.0 }
        fn (val: Size) [] { xy_pad.dim = val.0 }
    action:
}
*/

impl<'a, X, Y, F> ::draw::Drawable for XYPad<'a, X, Y, F>
    where
        X: Float + ToPrimitive + FromPrimitive + ToString,
        Y: Float + ToPrimitive + FromPrimitive + ToString,
        F: FnMut(X, Y) + 'a
{

    fn draw<B, C>(&mut self, uic: &mut UiContext<C>, graphics: &mut B)
        where
            B: Graphics<Texture = <C as CharacterCache>::Texture>,
            C: CharacterCache
    {

        // Init.
        let state = *get_state(uic, self.ui_id);
        let mouse = uic.get_mouse_state();
        let frame_w = self.maybe_frame.unwrap_or(uic.theme.frame_width);
        let frame_w2 = frame_w * 2.0;
        let maybe_frame = match frame_w > 0.0 {
            true => Some((frame_w, self.maybe_frame_color.unwrap_or(uic.theme.frame_color))),
            false => None,
        };
        let pad_dim = vec2_sub(self.dim, [frame_w2; 2]);
        let pad_pos = vec2_add(self.pos, [frame_w, frame_w]);
        let is_over_pad = rectangle::is_over(pad_pos, mouse.pos, pad_dim);
        let new_state = get_new_state(is_over_pad, state, mouse);

        // Determine new values.
        let (new_x, new_y) = match (is_over_pad, new_state) {
            (_, State::Normal) | (_, State::Highlighted) => (self.x, self.y),
            (_, State::Clicked) => {
                let temp_x = clamp(mouse.pos[0], pad_pos[0], pad_pos[0] + pad_dim[0]);
                let temp_y = clamp(mouse.pos[1], pad_pos[1], pad_pos[1] + pad_dim[1]);
                (map_range(temp_x - self.pos[0], pad_dim[0], 0.0, self.min_x, self.max_x),
                 map_range(temp_y - self.pos[1], pad_dim[1], 0.0, self.min_y, self.max_y))
            }
        };

        // Callback if value is changed or the pad is clicked/released.
        match self.maybe_callback {
            Some(ref mut callback) => {
                if self.x != new_x || self.y != new_y { (*callback)(new_x, new_y) }
                else {
                    match (state, new_state) {
                        (State::Highlighted, State::Clicked)
                        | (State::Clicked, State::Highlighted) => (*callback)(new_x, new_y),
                        _ => (),
                    }
                }
            },
            None => (),
        }

        // Draw.
        let rect_state = new_state.as_rectangle_state();
        let color = self.maybe_color.unwrap_or(uic.theme.shape_color);
        rectangle::draw(uic.win_w, uic.win_h, graphics, rect_state, self.pos,
                        self.dim, maybe_frame, color);
        let (vert_x, hori_y) = match (is_over_pad, new_state) {
            (_, State::Normal) | (_, State::Highlighted) =>
                (pad_pos[0] + map_range(new_x, self.min_x, self.max_x, pad_dim[0], 0.0),
                 pad_pos[1] + map_range(new_y, self.min_y, self.max_y, pad_dim[1], 0.0)),
            (_, State::Clicked) =>
                (clamp(mouse.pos[0], pad_pos[0], pad_pos[0] + pad_dim[0]),
                 clamp(mouse.pos[1], pad_pos[1], pad_pos[1] + pad_dim[1])),
        };
        // Crosshair.
        draw_crosshair(uic.win_w, uic.win_h, graphics, pad_pos, self.line_width,
                       vert_x, hori_y, pad_dim, color.plain_contrast());
        // Label.
        if let Some(l_text) = self.maybe_label {
            let l_color = self.maybe_label_color.unwrap_or(uic.theme.label_color);
            let l_size = self.maybe_label_font_size.unwrap_or(uic.theme.font_size_medium);
            let l_w = label::width(uic, l_size, l_text);
            let l_x = pad_pos[0] + (pad_dim[0] - l_w) / 2.0;
            let l_y = pad_pos[1] + (pad_dim[1] - l_size as f64) / 2.0;
            let l_pos = [l_x, l_y];
            uic.draw_text(graphics, l_pos, l_size, l_color, l_text);
        }
        // xy value string.
        let x_string = val_to_string(self.x, self.max_x,
                                     self.max_x - self.min_x, self.dim[0] as usize);
        let y_string = val_to_string(self.y, self.max_y,
                                     self.max_y - self.min_y, self.dim[1] as usize);
        let xy_string = format!("{}, {}", x_string, y_string);
        let xy_string_w = label::width(uic, self.font_size, &xy_string);
        let xy_string_pos = {
            match rectangle::corner(pad_pos, [vert_x, hori_y], pad_dim) {
                Corner::TopLeft => [vert_x, hori_y],
                Corner::TopRight => [vert_x - xy_string_w, hori_y],
                Corner::BottomLeft => [vert_x, hori_y - self.font_size as f64],
                Corner::BottomRight => [vert_x - xy_string_w, hori_y - self.font_size as f64],
            }
        };
        uic.draw_text(graphics, xy_string_pos, self.font_size,
                    color.plain_contrast(), &xy_string);

        set_state(uic, self.ui_id, Widget::XYPad(new_state), self.pos, self.dim);

    }
}
<|endoftext|>


<commit_before>s! {
    pub struct sigaction {
        pub sa_flags: ::c_uint,
        pub sa_sigaction: sighandler_t,
        pub sa_mask: sigset_t,
        _restorer: *mut ::c_void,
    }
}
<commit_msg>Fix undeclared type name errors when targeting android aarch64.<commit_after>s! {
    pub struct sigaction {
        pub sa_flags: ::c_uint,
        pub sa_sigaction: ::sighandler_t,
        pub sa_mask: ::sigset_t,
        _restorer: *mut ::c_void,
    }
}
<|endoftext|>


<commit_before>#[macro_use]
mod macros;

use proc_macro2::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream, TokenTree};
use quote::quote;
use std::iter::FromIterator;
use syn::{Expr, ExprRange};

#[test]
fn test_expr_parse() {
    let tokens = quote!(..100u32);
    snapshot!(tokens as Expr, @r###"
    Expr::Range {
        limits: HalfOpen,
        to: Some(Expr::Lit {
            lit: 100u32,
        }),
    }
    "###);

    let tokens = quote!(..100u32);
    snapshot!(tokens as ExprRange, @r###"
    ExprRange {
        limits: HalfOpen,
        to: Some(Expr::Lit {
            lit: 100u32,
        }),
    }
    "###);
}

#[test]
fn test_await() {
    // Must not parse as Expr::Field.
    let tokens = quote!(fut.await);

    snapshot!(tokens as Expr, @r###"
    Expr::Await {
        base: Expr::Path {
            path: Path {
                segments: [
                    PathSegment {
                        ident: "fut",
                        arguments: None,
                    },
                ],
            },
        },
    }
    "###);
}

#[rustfmt::skip]
#[test]
fn test_tuple_multi_index() {
    for &input in &[
        "tuple.0.0",
        "tuple .0.0",
        "tuple. 0.0",
        "tuple.0 .0",
        "tuple.0. 0",
        "tuple . 0 . 0",
    ] {
        snapshot!(input as Expr, @r###"
        Expr::Field {
            base: Expr::Field {
                base: Expr::Path {
                    path: Path {
                        segments: [
                            PathSegment {
                                ident: "tuple",
                                arguments: None,
                            },
                        ],
                    },
                },
                member: Unnamed(Index {
                    index: 0,
                }),
            },
            member: Unnamed(Index {
                index: 0,
            }),
        }
        "###);
    }

    for tokens in vec![
        quote!(tuple.0.0),
        quote!(tuple .0.0),
        quote!(tuple. 0.0),
        quote!(tuple.0 .0),
        quote!(tuple.0. 0),
        quote!(tuple . 0 . 0),
    ] {
        snapshot!(tokens as Expr, @r###"
        Expr::Field {
            base: Expr::Field {
                base: Expr::Path {
                    path: Path {
                        segments: [
                            PathSegment {
                                ident: "tuple",
                                arguments: None,
                            },
                        ],
                    },
                },
                member: Unnamed(Index {
                    index: 0,
                }),
            },
            member: Unnamed(Index {
                index: 0,
            }),
        }
        "###);
    }
}

#[test]
fn test_macro_variable_func() {
    // mimics the token stream corresponding to `$fn()`
    let tokens = TokenStream::from_iter(vec![
        TokenTree::Group(Group::new(Delimiter::None, quote! { f })),
        TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::new())),
    ]);

    snapshot!(tokens as Expr, @r###"
    Expr::Call {
        func: Expr::Group {
            expr: Expr::Path {
                path: Path {
                    segments: [
                        PathSegment {
                            ident: "f",
                            arguments: None,
                        },
                    ],
                },
            },
        },
    }
    "###);

    let tokens = TokenStream::from_iter(vec![
        TokenTree::Punct(Punct::new('#', Spacing::Alone)),
        TokenTree::Group(Group::new(Delimiter::Bracket, quote! { outside })),
        TokenTree::Group(Group::new(Delimiter::None, quote! { #[inside] f })),
        TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::new())),
    ]);

    snapshot!(tokens as Expr, @r###"
    Expr::Call {
        attrs: [
            Attribute {
                style: Outer,
                path: Path {
                    segments: [
                        PathSegment {
                            ident: "outside",
                            arguments: None,
                        },
                    ],
                },
                tokens: TokenStream(``),
            },
        ],
        func: Expr::Group {
            expr: Expr::Path {
                attrs: [
                    Attribute {
                        style: Outer,
                        path: Path {
                            segments: [
                                PathSegment {
                                    ident: "inside",
                                    arguments: None,
                                },
                            ],
                        },
                        tokens: TokenStream(``),
                    },
                ],
                path: Path {
                    segments: [
                        PathSegment {
                            ident: "f",
                            arguments: None,
                        },
                    ],
                },
            },
        },
    }
    "###);
}

#[test]
fn test_macro_variable_macro() {
    // mimics the token stream corresponding to `$macro!()`
    let tokens = TokenStream::from_iter(vec![
        TokenTree::Group(Group::new(Delimiter::None, quote! { m })),
        TokenTree::Punct(Punct::new('!', Spacing::Alone)),
        TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::new())),
    ]);

    snapshot!(tokens as Expr, @r###"
    Expr::Macro {
        mac: Macro {
            path: Path {
                segments: [
                    PathSegment {
                        ident: "m",
                        arguments: None,
                    },
                ],
            },
            delimiter: Paren,
            tokens: TokenStream(``),
        },
    }
    "###);
}

#[test]
fn test_macro_variable_struct() {
    // mimics the token stream corresponding to `$struct {}`
    let tokens = TokenStream::from_iter(vec![
        TokenTree::Group(Group::new(Delimiter::None, quote! { S })),
        TokenTree::Group(Group::new(Delimiter::Brace, TokenStream::new())),
    ]);

    snapshot!(tokens as Expr, @r###"
    Expr::Struct {
        path: Path {
            segments: [
                PathSegment {
                    ident: "S",
                    arguments: None,
                },
            ],
        },
    }
    "###);
}

#[test]
fn test_macro_variable_match_arm() {
    // mimics the token stream corresponding to `match v { _ => $expr }`
    let tokens = TokenStream::from_iter(vec![
        TokenTree::Ident(Ident::new("match", Span::call_site())),
        TokenTree::Ident(Ident::new("v", Span::call_site())),
        TokenTree::Group(Group::new(
            Delimiter::Brace,
            TokenStream::from_iter(vec![
                TokenTree::Punct(Punct::new('_', Spacing::Alone)),
                TokenTree::Punct(Punct::new('=', Spacing::Joint)),
                TokenTree::Punct(Punct::new('>', Spacing::Alone)),
                TokenTree::Group(Group::new(Delimiter::None, quote! { #[a] () })),
            ]),
        )),
    ]);

    snapshot!(tokens as Expr, @r###"
    Expr::Match {
        expr: Expr::Path {
            path: Path {
                segments: [
                    PathSegment {
                        ident: "v",
                        arguments: None,
                    },
                ],
            },
        },
        arms: [
            Arm {
                pat: Pat::Wild,
                body: Expr::Group {
                    expr: Expr::Tuple {
                        attrs: [
                            Attribute {
                                style: Outer,
                                path: Path {
                                    segments: [
                                        PathSegment {
                                            ident: "a",
                                            arguments: None,
                                        },
                                    ],
                                },
                                tokens: TokenStream(``),
                            },
                        ],
                    },
                },
            },
        ],
    }
    "###);
}

// https://github.com/dtolnay/syn/issues/1019
#[test]
fn test_closure_vs_rangefull() {
    #[rustfmt::skip] // rustfmt bug: https://github.com/rust-lang/rustfmt/issues/4808
    let tokens = quote!(|| .. .method());
    snapshot!(tokens as Expr, @r###"
    Expr::MethodCall {
        receiver: Expr::Closure {
            output: Default,
            body: Expr::Range {
                limits: HalfOpen,
            },
        },
        method: "method",
    }
    "###);
}
<commit_msg>Add cast tests that should fail to parse<commit_after>#[macro_use]
mod macros;

use proc_macro2::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream, TokenTree};
use quote::quote;
use std::iter::FromIterator;
use syn::{Expr, ExprRange};

#[test]
fn test_expr_parse() {
    let tokens = quote!(..100u32);
    snapshot!(tokens as Expr, @r###"
    Expr::Range {
        limits: HalfOpen,
        to: Some(Expr::Lit {
            lit: 100u32,
        }),
    }
    "###);

    let tokens = quote!(..100u32);
    snapshot!(tokens as ExprRange, @r###"
    ExprRange {
        limits: HalfOpen,
        to: Some(Expr::Lit {
            lit: 100u32,
        }),
    }
    "###);
}

#[test]
fn test_await() {
    // Must not parse as Expr::Field.
    let tokens = quote!(fut.await);

    snapshot!(tokens as Expr, @r###"
    Expr::Await {
        base: Expr::Path {
            path: Path {
                segments: [
                    PathSegment {
                        ident: "fut",
                        arguments: None,
                    },
                ],
            },
        },
    }
    "###);
}

#[rustfmt::skip]
#[test]
fn test_tuple_multi_index() {
    for &input in &[
        "tuple.0.0",
        "tuple .0.0",
        "tuple. 0.0",
        "tuple.0 .0",
        "tuple.0. 0",
        "tuple . 0 . 0",
    ] {
        snapshot!(input as Expr, @r###"
        Expr::Field {
            base: Expr::Field {
                base: Expr::Path {
                    path: Path {
                        segments: [
                            PathSegment {
                                ident: "tuple",
                                arguments: None,
                            },
                        ],
                    },
                },
                member: Unnamed(Index {
                    index: 0,
                }),
            },
            member: Unnamed(Index {
                index: 0,
            }),
        }
        "###);
    }

    for tokens in vec![
        quote!(tuple.0.0),
        quote!(tuple .0.0),
        quote!(tuple. 0.0),
        quote!(tuple.0 .0),
        quote!(tuple.0. 0),
        quote!(tuple . 0 . 0),
    ] {
        snapshot!(tokens as Expr, @r###"
        Expr::Field {
            base: Expr::Field {
                base: Expr::Path {
                    path: Path {
                        segments: [
                            PathSegment {
                                ident: "tuple",
                                arguments: None,
                            },
                        ],
                    },
                },
                member: Unnamed(Index {
                    index: 0,
                }),
            },
            member: Unnamed(Index {
                index: 0,
            }),
        }
        "###);
    }
}

#[test]
fn test_macro_variable_func() {
    // mimics the token stream corresponding to `$fn()`
    let tokens = TokenStream::from_iter(vec![
        TokenTree::Group(Group::new(Delimiter::None, quote! { f })),
        TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::new())),
    ]);

    snapshot!(tokens as Expr, @r###"
    Expr::Call {
        func: Expr::Group {
            expr: Expr::Path {
                path: Path {
                    segments: [
                        PathSegment {
                            ident: "f",
                            arguments: None,
                        },
                    ],
                },
            },
        },
    }
    "###);

    let tokens = TokenStream::from_iter(vec![
        TokenTree::Punct(Punct::new('#', Spacing::Alone)),
        TokenTree::Group(Group::new(Delimiter::Bracket, quote! { outside })),
        TokenTree::Group(Group::new(Delimiter::None, quote! { #[inside] f })),
        TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::new())),
    ]);

    snapshot!(tokens as Expr, @r###"
    Expr::Call {
        attrs: [
            Attribute {
                style: Outer,
                path: Path {
                    segments: [
                        PathSegment {
                            ident: "outside",
                            arguments: None,
                        },
                    ],
                },
                tokens: TokenStream(``),
            },
        ],
        func: Expr::Group {
            expr: Expr::Path {
                attrs: [
                    Attribute {
                        style: Outer,
                        path: Path {
                            segments: [
                                PathSegment {
                                    ident: "inside",
                                    arguments: None,
                                },
                            ],
                        },
                        tokens: TokenStream(``),
                    },
                ],
                path: Path {
                    segments: [
                        PathSegment {
                            ident: "f",
                            arguments: None,
                        },
                    ],
                },
            },
        },
    }
    "###);
}

#[test]
fn test_macro_variable_macro() {
    // mimics the token stream corresponding to `$macro!()`
    let tokens = TokenStream::from_iter(vec![
        TokenTree::Group(Group::new(Delimiter::None, quote! { m })),
        TokenTree::Punct(Punct::new('!', Spacing::Alone)),
        TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::new())),
    ]);

    snapshot!(tokens as Expr, @r###"
    Expr::Macro {
        mac: Macro {
            path: Path {
                segments: [
                    PathSegment {
                        ident: "m",
                        arguments: None,
                    },
                ],
            },
            delimiter: Paren,
            tokens: TokenStream(``),
        },
    }
    "###);
}

#[test]
fn test_macro_variable_struct() {
    // mimics the token stream corresponding to `$struct {}`
    let tokens = TokenStream::from_iter(vec![
        TokenTree::Group(Group::new(Delimiter::None, quote! { S })),
        TokenTree::Group(Group::new(Delimiter::Brace, TokenStream::new())),
    ]);

    snapshot!(tokens as Expr, @r###"
    Expr::Struct {
        path: Path {
            segments: [
                PathSegment {
                    ident: "S",
                    arguments: None,
                },
            ],
        },
    }
    "###);
}

#[test]
fn test_macro_variable_match_arm() {
    // mimics the token stream corresponding to `match v { _ => $expr }`
    let tokens = TokenStream::from_iter(vec![
        TokenTree::Ident(Ident::new("match", Span::call_site())),
        TokenTree::Ident(Ident::new("v", Span::call_site())),
        TokenTree::Group(Group::new(
            Delimiter::Brace,
            TokenStream::from_iter(vec![
                TokenTree::Punct(Punct::new('_', Spacing::Alone)),
                TokenTree::Punct(Punct::new('=', Spacing::Joint)),
                TokenTree::Punct(Punct::new('>', Spacing::Alone)),
                TokenTree::Group(Group::new(Delimiter::None, quote! { #[a] () })),
            ]),
        )),
    ]);

    snapshot!(tokens as Expr, @r###"
    Expr::Match {
        expr: Expr::Path {
            path: Path {
                segments: [
                    PathSegment {
                        ident: "v",
                        arguments: None,
                    },
                ],
            },
        },
        arms: [
            Arm {
                pat: Pat::Wild,
                body: Expr::Group {
                    expr: Expr::Tuple {
                        attrs: [
                            Attribute {
                                style: Outer,
                                path: Path {
                                    segments: [
                                        PathSegment {
                                            ident: "a",
                                            arguments: None,
                                        },
                                    ],
                                },
                                tokens: TokenStream(``),
                            },
                        ],
                    },
                },
            },
        ],
    }
    "###);
}

// https://github.com/dtolnay/syn/issues/1019
#[test]
fn test_closure_vs_rangefull() {
    #[rustfmt::skip] // rustfmt bug: https://github.com/rust-lang/rustfmt/issues/4808
    let tokens = quote!(|| .. .method());
    snapshot!(tokens as Expr, @r###"
    Expr::MethodCall {
        receiver: Expr::Closure {
            output: Default,
            body: Expr::Range {
                limits: HalfOpen,
            },
        },
        method: "method",
    }
    "###);
}

#[test]
fn test_postfix_operator_after_cast() {
    syn::parse_str::<Expr>("|| &x as T[0]").unwrap(); // FIXME
    syn::parse_str::<Expr>("|| () as ()()").unwrap(); // FIXME
}
<|endoftext|>


<commit_before>use naulang::interpreter::frame::Frame;
use naulang::interpreter::bytecode::Bytecode;
use naulang::interpreter::task::Task;

pub fn interpreter_step(task: &mut Task) -> bool {
    match task.top_frame {
        Some(frame) => run_interpreter_step(frame, task),
        None => false
    }
}

fn run_interpreter_step(frame: &Box<Frame>, task: &mut Task) -> bool {
    let bytecode = frame.method.get_bytecode(frame.pc);

    match bytecode {
        Bytecode::HALT => task.restore_previous_frame_or_halt(),
        _ => false // Not implemented
    }
}

#[cfg(test)]
mod tests {
    use super::interpreter_step;
    use naulang::objectspace::method::MethodObject;
    use naulang::objectspace::primitives::{Object, IntegerObject};
    use naulang::interpreter::frame::{Frame, FrameInfo};
    use naulang::interpreter::task::{Task, TaskState};
    use naulang::interpreter::bytecode::Bytecode;

    #[test]
    fn test_interpreter_step_task_load_const() {
        let literal = Object::Integer(IntegerObject { value: 42 });
        let literals = vec!(literal);

        let mut load_const_method = MethodObject::new(vec!(
            Bytecode::LOAD_CONST, 0,
            Bytecode::HALT
        ), &literals, 0);

        let stack_root = Frame::new(FrameInfo {
            stack_depth: 1,
            local_count: 0,
            literal_count: 1,
            method: &load_const_method,
        });

        let mut task = Task::new_withframe(&stack_root, Option::None);
        let step_result = interpreter_step(&mut task);
        assert!(step_result);
//        stack_root.peek()
    }

    #[test]
    fn test_interepreter_step_task_halt() {
        let literals = vec!();
        let halting_method = MethodObject::new(vec!(Bytecode::HALT), &literals, 0);
        let stack_root = Frame::new(FrameInfo {
            stack_depth: 0,
            local_count: 0,
            literal_count: 0,
            method: &halting_method
        });

        let mut task = Task::new_withframe(&stack_root, Option::None);

        let step_result = interpreter_step(&mut task);

        assert!(!step_result);
        assert!(task.state == TaskState::Halt);

    }
}
<commit_msg>Ignore test<commit_after>use naulang::interpreter::frame::Frame;
use naulang::interpreter::bytecode::Bytecode;
use naulang::interpreter::task::Task;

pub fn interpreter_step(task: &mut Task) -> bool {
    match task.top_frame {
        Some(frame) => run_interpreter_step(frame, task),
        None => false
    }
}

fn run_interpreter_step(frame: &Box<Frame>, task: &mut Task) -> bool {
    let bytecode = frame.method.get_bytecode(frame.pc);

    match bytecode {
        Bytecode::HALT => task.restore_previous_frame_or_halt(),
        _ => false // Not implemented
    }
}

#[cfg(test)]
mod tests {
    use super::interpreter_step;
    use naulang::objectspace::method::MethodObject;
    use naulang::objectspace::primitives::{Object, IntegerObject};
    use naulang::interpreter::frame::{Frame, FrameInfo};
    use naulang::interpreter::task::{Task, TaskState};
    use naulang::interpreter::bytecode::Bytecode;

    #[test]
    #[ignore]
    fn test_interpreter_step_task_load_const() {
        let literal = Object::Integer(IntegerObject { value: 42 });
        let literals = vec!(literal);

        let mut load_const_method = MethodObject::new(vec!(
            Bytecode::LOAD_CONST, 0,
            Bytecode::HALT
        ), &literals, 0);

        let stack_root = Frame::new(FrameInfo {
            stack_depth: 1,
            local_count: 0,
            literal_count: 1,
            method: &load_const_method,
        });

        let mut task = Task::new_withframe(&stack_root, Option::None);
        let step_result = interpreter_step(&mut task);
        assert!(step_result);
//        stack_root.peek()
    }

    #[test]
    fn test_interepreter_step_task_halt() {
        let literals = vec!();
        let halting_method = MethodObject::new(vec!(Bytecode::HALT), &literals, 0);
        let stack_root = Frame::new(FrameInfo {
            stack_depth: 0,
            local_count: 0,
            literal_count: 0,
            method: &halting_method
        });

        let mut task = Task::new_withframe(&stack_root, Option::None);

        let step_result = interpreter_step(&mut task);

        assert!(!step_result);
        assert!(task.state == TaskState::Halt);

    }
}
<|endoftext|>