<commit_before>mod reader;
mod writer;

pub use self::reader::MultiValuedFastFieldReader;
pub use self::writer::MultiValuedFastFieldWriter;

#[cfg(test)]
mod tests {

    use crate::collector::TopDocs;
    use crate::query::QueryParser;
    use crate::schema::Cardinality;
    use crate::schema::Facet;
    use crate::schema::IntOptions;
    use crate::schema::Schema;
    use crate::schema::INDEXED;
    use crate::Index;
    use chrono::Duration;

    #[test]
    fn test_multivalued_u64() {
        let mut schema_builder = Schema::builder();
        let field = schema_builder.add_u64_field(
            "multifield",
            IntOptions::default().set_fast(Cardinality::MultiValues),
        );
        let schema = schema_builder.build();
        let index = Index::create_in_ram(schema);
        let mut index_writer = index.writer_for_tests().unwrap();
        index_writer.add_document(doc!(field=>1u64, field=>3u64));
        index_writer.add_document(doc!());
        index_writer.add_document(doc!(field=>4u64));
        index_writer.add_document(doc!(field=>5u64, field=>20u64,field=>1u64));
        assert!(index_writer.commit().is_ok());

        let searcher = index.reader().unwrap().searcher();
        let segment_reader = searcher.segment_reader(0);
        let mut vals = Vec::new();
        let multi_value_reader = segment_reader.fast_fields().u64s(field).unwrap();
        {
            multi_value_reader.get_vals(2, &mut vals);
            assert_eq!(&vals, &[4u64]);
        }
        {
            multi_value_reader.get_vals(0, &mut vals);
            assert_eq!(&vals, &[1u64, 3u64]);
        }
        {
            multi_value_reader.get_vals(1, &mut vals);
            assert!(vals.is_empty());
        }
    }

    #[test]
    fn test_multivalued_date() {
        let mut schema_builder = Schema::builder();
        let date_field = schema_builder.add_date_field(
            "multi_date_field",
            IntOptions::default()
                .set_fast(Cardinality::MultiValues)
                .set_indexed()
                .set_stored(),
        );
        let time_i =
            schema_builder.add_i64_field("time_stamp_i", IntOptions::default().set_stored());
        let schema = schema_builder.build();
        let index = Index::create_in_ram(schema);
        let mut index_writer = index.writer_for_tests().unwrap();
        let first_time_stamp = chrono::Utc::now();
        index_writer.add_document(
            doc!(date_field=>first_time_stamp, date_field=>first_time_stamp, time_i=>1i64),
        );
        index_writer.add_document(doc!(time_i=>0i64));
        // add one second
        index_writer
            .add_document(doc!(date_field=>first_time_stamp + Duration::seconds(1), time_i=>2i64));
        // add another second
        let two_secs_ahead = first_time_stamp + Duration::seconds(2);
        index_writer.add_document(doc!(date_field=>two_secs_ahead, date_field=>two_secs_ahead,date_field=>two_secs_ahead, time_i=>3i64));
        assert!(index_writer.commit().is_ok());

        let reader = index.reader().unwrap();
        let searcher = reader.searcher();
        let reader = searcher.segment_reader(0);
        assert_eq!(reader.num_docs(), 4);

        {
            let parser = QueryParser::for_index(&index, vec![date_field]);
            let query = parser
                .parse_query(&format!("\"{}\"", first_time_stamp.to_rfc3339()).to_string())
                .expect("could not parse query");
            let results = searcher
                .search(&query, &TopDocs::with_limit(5))
                .expect("could not query index");

            assert_eq!(results.len(), 1);
            for (_score, doc_address) in results {
                let retrieved_doc = searcher.doc(doc_address).expect("cannot fetch doc");
                assert_eq!(
                    retrieved_doc
                        .get_first(date_field)
                        .expect("cannot find value")
                        .date_value()
                        .unwrap()
                        .timestamp(),
                    first_time_stamp.timestamp()
                );
                assert_eq!(
                    retrieved_doc
                        .get_first(time_i)
                        .expect("cannot find value")
                        .i64_value(),
                    Some(1i64)
                );
            }
        }

        {
            let parser = QueryParser::for_index(&index, vec![date_field]);
            let query = parser
                .parse_query(&format!("\"{}\"", two_secs_ahead.to_rfc3339()).to_string())
                .expect("could not parse query");
            let results = searcher
                .search(&query, &TopDocs::with_limit(5))
                .expect("could not query index");

            assert_eq!(results.len(), 1);

            for (_score, doc_address) in results {
                let retrieved_doc = searcher.doc(doc_address).expect("cannot fetch doc");
                assert_eq!(
                    retrieved_doc
                        .get_first(date_field)
                        .expect("cannot find value")
                        .date_value()
                        .unwrap()
                        .timestamp(),
                    two_secs_ahead.timestamp()
                );
                assert_eq!(
                    retrieved_doc
                        .get_first(time_i)
                        .expect("cannot find value")
                        .i64_value(),
                    Some(3i64)
                );
            }
        }

        {
            let parser = QueryParser::for_index(&index, vec![date_field]);
            let range_q = format!(
                "[{} TO {}]",
                (first_time_stamp + Duration::seconds(1)).to_rfc3339(),
                (first_time_stamp + Duration::seconds(3)).to_rfc3339()
            );
            let query = parser.parse_query(&range_q).expect("could not parse query");
            let results = searcher
                .search(&query, &TopDocs::with_limit(5))
                .expect("could not query index");

            assert_eq!(results.len(), 2);
            for (i, doc_pair) in results.iter().enumerate() {
                let retrieved_doc = searcher.doc(doc_pair.1).expect("cannot fetch doc");
                let offset_sec = match i {
                    0 => 1,
                    1 => 2, // TODO! changed so that the test passes
                    _ => panic!("should not have more than 2 docs"),
                };
                let time_i_val = match i {
                    0 => 2,
                    1 => 3,
                    _ => panic!("should not have more than 2 docs"),
                };
                assert_eq!(
                    retrieved_doc
                        .get_first(date_field)
                        .expect("cannot find value")
                        .date_value()
                        .expect("value not of Date type")
                        .timestamp(),
                    (first_time_stamp + Duration::seconds(offset_sec)).timestamp()
                );
                assert_eq!(
                    retrieved_doc
                        .get_first(time_i)
                        .expect("cannot find value")
                        .i64_value()
                        .expect("value not of i64 type"),
                    time_i_val
                );
            }
        }
    }

    #[test]
    fn test_multivalued_i64() {
        let mut schema_builder = Schema::builder();
        let field = schema_builder.add_i64_field(
            "multifield",
            IntOptions::default().set_fast(Cardinality::MultiValues),
        );
        let schema = schema_builder.build();
        let index = Index::create_in_ram(schema);
        let mut index_writer = index.writer_for_tests().unwrap();
        index_writer.add_document(doc!(field=> 1i64, field => 3i64));
        index_writer.add_document(doc!());
        index_writer.add_document(doc!(field=> -4i64));
        index_writer.add_document(doc!(field=> -5i64, field => -20i64, field=>1i64));
        assert!(index_writer.commit().is_ok());

        let searcher = index.reader().unwrap().searcher();
        let segment_reader = searcher.segment_reader(0);
        let mut vals = Vec::new();
        let multi_value_reader = segment_reader.fast_fields().i64s(field).unwrap();
        multi_value_reader.get_vals(2, &mut vals);
        assert_eq!(&vals, &[-4i64]);
        multi_value_reader.get_vals(0, &mut vals);
        assert_eq!(&vals, &[1i64, 3i64]);
        multi_value_reader.get_vals(1, &mut vals);
        assert!(vals.is_empty());
        multi_value_reader.get_vals(3, &mut vals);
        assert_eq!(&vals, &[-5i64, -20i64, 1i64]);
    }
    #[test]
    #[ignore]
    fn test_many_facets() {
        let mut schema_builder = Schema::builder();
        let field = schema_builder.add_facet_field("facetfield", INDEXED);
        let schema = schema_builder.build();
        let index = Index::create_in_ram(schema);
        let mut index_writer = index.writer_for_tests().unwrap();
        for i in 0..100_000 {
            index_writer.add_document(doc!(field=> Facet::from(format!("/lang/{}", i).as_str())));
        }
        assert!(index_writer.commit().is_ok());
    }
}
<commit_msg>Verified that the change in datetime range test was correct<commit_after>mod reader;
mod writer;

pub use self::reader::MultiValuedFastFieldReader;
pub use self::writer::MultiValuedFastFieldWriter;

#[cfg(test)]
mod tests {

    use crate::collector::TopDocs;
    use crate::query::QueryParser;
    use crate::schema::Cardinality;
    use crate::schema::Facet;
    use crate::schema::IntOptions;
    use crate::schema::Schema;
    use crate::schema::INDEXED;
    use crate::Index;
    use chrono::Duration;

    #[test]
    fn test_multivalued_u64() {
        let mut schema_builder = Schema::builder();
        let field = schema_builder.add_u64_field(
            "multifield",
            IntOptions::default().set_fast(Cardinality::MultiValues),
        );
        let schema = schema_builder.build();
        let index = Index::create_in_ram(schema);
        let mut index_writer = index.writer_for_tests().unwrap();
        index_writer.add_document(doc!(field=>1u64, field=>3u64));
        index_writer.add_document(doc!());
        index_writer.add_document(doc!(field=>4u64));
        index_writer.add_document(doc!(field=>5u64, field=>20u64,field=>1u64));
        assert!(index_writer.commit().is_ok());

        let searcher = index.reader().unwrap().searcher();
        let segment_reader = searcher.segment_reader(0);
        let mut vals = Vec::new();
        let multi_value_reader = segment_reader.fast_fields().u64s(field).unwrap();
        {
            multi_value_reader.get_vals(2, &mut vals);
            assert_eq!(&vals, &[4u64]);
        }
        {
            multi_value_reader.get_vals(0, &mut vals);
            assert_eq!(&vals, &[1u64, 3u64]);
        }
        {
            multi_value_reader.get_vals(1, &mut vals);
            assert!(vals.is_empty());
        }
    }

    #[test]
    fn test_multivalued_date() {
        let mut schema_builder = Schema::builder();
        let date_field = schema_builder.add_date_field(
            "multi_date_field",
            IntOptions::default()
                .set_fast(Cardinality::MultiValues)
                .set_indexed()
                .set_stored(),
        );
        let time_i =
            schema_builder.add_i64_field("time_stamp_i", IntOptions::default().set_stored());
        let schema = schema_builder.build();
        let index = Index::create_in_ram(schema);
        let mut index_writer = index.writer_for_tests().unwrap();
        let first_time_stamp = chrono::Utc::now();
        index_writer.add_document(
            doc!(date_field=>first_time_stamp, date_field=>first_time_stamp, time_i=>1i64),
        );
        index_writer.add_document(doc!(time_i=>0i64));
        // add one second
        index_writer
            .add_document(doc!(date_field=>first_time_stamp + Duration::seconds(1), time_i=>2i64));
        // add another second
        let two_secs_ahead = first_time_stamp + Duration::seconds(2);
        index_writer.add_document(doc!(date_field=>two_secs_ahead, date_field=>two_secs_ahead,date_field=>two_secs_ahead, time_i=>3i64));
        assert!(index_writer.commit().is_ok());

        let reader = index.reader().unwrap();
        let searcher = reader.searcher();
        let reader = searcher.segment_reader(0);
        assert_eq!(reader.num_docs(), 4);

        {
            let parser = QueryParser::for_index(&index, vec![date_field]);
            let query = parser
                .parse_query(&format!("\"{}\"", first_time_stamp.to_rfc3339()).to_string())
                .expect("could not parse query");
            let results = searcher
                .search(&query, &TopDocs::with_limit(5))
                .expect("could not query index");

            assert_eq!(results.len(), 1);
            for (_score, doc_address) in results {
                let retrieved_doc = searcher.doc(doc_address).expect("cannot fetch doc");
                assert_eq!(
                    retrieved_doc
                        .get_first(date_field)
                        .expect("cannot find value")
                        .date_value()
                        .unwrap()
                        .timestamp(),
                    first_time_stamp.timestamp()
                );
                assert_eq!(
                    retrieved_doc
                        .get_first(time_i)
                        .expect("cannot find value")
                        .i64_value(),
                    Some(1i64)
                );
            }
        }

        {
            let parser = QueryParser::for_index(&index, vec![date_field]);
            let query = parser
                .parse_query(&format!("\"{}\"", two_secs_ahead.to_rfc3339()).to_string())
                .expect("could not parse query");
            let results = searcher
                .search(&query, &TopDocs::with_limit(5))
                .expect("could not query index");

            assert_eq!(results.len(), 1);

            for (_score, doc_address) in results {
                let retrieved_doc = searcher.doc(doc_address).expect("cannot fetch doc");
                assert_eq!(
                    retrieved_doc
                        .get_first(date_field)
                        .expect("cannot find value")
                        .date_value()
                        .unwrap()
                        .timestamp(),
                    two_secs_ahead.timestamp()
                );
                assert_eq!(
                    retrieved_doc
                        .get_first(time_i)
                        .expect("cannot find value")
                        .i64_value(),
                    Some(3i64)
                );
            }
        }

        {
            let parser = QueryParser::for_index(&index, vec![date_field]);
            let range_q = format!(
                "[{} TO {}]",
                (first_time_stamp + Duration::seconds(1)).to_rfc3339(),
                (first_time_stamp + Duration::seconds(3)).to_rfc3339()
            );
            let query = parser.parse_query(&range_q).expect("could not parse query");
            let results = searcher
                .search(&query, &TopDocs::with_limit(5))
                .expect("could not query index");

            assert_eq!(results.len(), 2);
            for (i, doc_pair) in results.iter().enumerate() {
                let retrieved_doc = searcher.doc(doc_pair.1).expect("cannot fetch doc");
                let offset_sec = match i {
                    0 => 1,
                    1 => 2,
                    _ => panic!("should not have more than 2 docs"),
                };
                let time_i_val = match i {
                    0 => 2,
                    1 => 3,
                    _ => panic!("should not have more than 2 docs"),
                };
                assert_eq!(
                    retrieved_doc
                        .get_first(date_field)
                        .expect("cannot find value")
                        .date_value()
                        .expect("value not of Date type")
                        .timestamp(),
                    (first_time_stamp + Duration::seconds(offset_sec)).timestamp()
                );
                assert_eq!(
                    retrieved_doc
                        .get_first(time_i)
                        .expect("cannot find value")
                        .i64_value()
                        .expect("value not of i64 type"),
                    time_i_val
                );
            }
        }
    }

    #[test]
    fn test_multivalued_i64() {
        let mut schema_builder = Schema::builder();
        let field = schema_builder.add_i64_field(
            "multifield",
            IntOptions::default().set_fast(Cardinality::MultiValues),
        );
        let schema = schema_builder.build();
        let index = Index::create_in_ram(schema);
        let mut index_writer = index.writer_for_tests().unwrap();
        index_writer.add_document(doc!(field=> 1i64, field => 3i64));
        index_writer.add_document(doc!());
        index_writer.add_document(doc!(field=> -4i64));
        index_writer.add_document(doc!(field=> -5i64, field => -20i64, field=>1i64));
        assert!(index_writer.commit().is_ok());

        let searcher = index.reader().unwrap().searcher();
        let segment_reader = searcher.segment_reader(0);
        let mut vals = Vec::new();
        let multi_value_reader = segment_reader.fast_fields().i64s(field).unwrap();
        multi_value_reader.get_vals(2, &mut vals);
        assert_eq!(&vals, &[-4i64]);
        multi_value_reader.get_vals(0, &mut vals);
        assert_eq!(&vals, &[1i64, 3i64]);
        multi_value_reader.get_vals(1, &mut vals);
        assert!(vals.is_empty());
        multi_value_reader.get_vals(3, &mut vals);
        assert_eq!(&vals, &[-5i64, -20i64, 1i64]);
    }
    #[test]
    #[ignore]
    fn test_many_facets() {
        let mut schema_builder = Schema::builder();
        let field = schema_builder.add_facet_field("facetfield", INDEXED);
        let schema = schema_builder.build();
        let index = Index::create_in_ram(schema);
        let mut index_writer = index.writer_for_tests().unwrap();
        for i in 0..100_000 {
            index_writer.add_document(doc!(field=> Facet::from(format!("/lang/{}", i).as_str())));
        }
        assert!(index_writer.commit().is_ok());
    }
}
<|endoftext|>


<commit_before>// "Tifflin" Kernel
// - By John Hodge (thePowersGang)
//
// Core/main.rs
//! Low-level interrupt handling and CPU error handling
use prelude::*;
use super::{puts,puth};
use super::log::puth64;

#[repr(C)]
//#[derive(Copy,Clone)]
/// Register state as saved by the error ISR handler
pub struct InterruptRegs
{
	//fs: u64,
	gs: u64,

	rax: u64, rcx: u64, rdx: u64, rbx: u64,
	/*no rsp*/rbp: u64, rsi: u64, rdi: u64,
	r8: u64,  r9: u64,  r10: u64, r11: u64,
	r12: u64, r13: u64, r14: u64, r15: u64,

	intnum: u64, errorcode: u64,
	rip: u64, cs: u64,
	rflags: u64, rsp: u64, ss: u64,
}

#[repr(C)]
/// A handler for an ISR
pub type ISRHandler = extern "C" fn(isrnum: usize,info:*const(),idx:usize);

struct IRQHandlersEnt
{
	handler: Option<ISRHandler>,
	info: *const(),
	idx: usize,
}
impl Copy for IRQHandlersEnt {}
impl Clone for IRQHandlersEnt { fn clone(&self)->Self { *self } }
unsafe impl Send for IRQHandlersEnt {}

#[derive(Default)]
/// A handle for a bound ISR, unbound on drop
pub struct ISRHandle
{
	idx: usize,
}

#[allow(non_upper_case_globals)]
static s_irq_handlers_lock: ::sync::Mutex<[IRQHandlersEnt; 256]> = ::sync::Mutex::new( [IRQHandlersEnt{
	handler: None,
	info: 0 as *const _,
	idx: 0
	}; 256] );

#[no_mangle]
#[doc(hidden)]
/// ISR handler called by assembly
pub extern "C" fn irq_handler(index: usize)
{
	let lh = s_irq_handlers_lock.lock();
	let ent = (*lh)[index];
	if let Some(h) = ent.handler {
		(h)(index, ent.info, ent.idx);
	}
}

#[no_mangle]
#[doc(hidden)]
/// Error handler called by assembly
pub extern "C" fn error_handler(regs: &InterruptRegs)
{
	match regs.intnum
	{
	13 => { puts("GPF ("); puth(regs.errorcode); puts(")\n"); },
	14 => {
		let cr2;
		// SAFE: Just reads CR2
		unsafe { asm!("mov %cr2, $0" : "=r" (cr2)) };
		puts("PF ("); puth(regs.errorcode); puts(") at "); puth(cr2 as u64); puts(" by "); puth(regs.rip); puts("\n");
		if ::arch::memory::virt::handle_page_fault(cr2, regs.errorcode as u32) {
			return ;
		}
		},
	_ => { puts("ERROR "); puth(regs.intnum); puts(" (code "); puth(regs.errorcode); puts(")\n"); },
	}
	puts("CS:RIP  = "); puth(regs.cs); puts(":"); puth(regs.rip); puts("\n");
	puts("SS:RSP  = "); puth(regs.ss); puts(":"); puth(regs.rsp); puts("\n");
	puts("CR2 = "); puth(get_cr2()); puts("\n");
	puts("RAX "); puth64(regs.rax); puts("  RCX "); puth64(regs.rcx); puts("  ");
	puts("RDX "); puth64(regs.rdx); puts("  RBX "); puth64(regs.rbx); puts("\n");
	puts("RSI "); puth64(regs.rsi); puts("  RDI "); puth64(regs.rdi); puts("  ");
	puts("RSP "); puth64(regs.rsp); puts("  RBP "); puth64(regs.rbp); puts("\n");
	puts("R8  "); puth64(regs.r8 ); puts("  R9  "); puth64(regs.r9 ); puts("  ");
	puts("R10 "); puth64(regs.r10); puts("  R11 "); puth64(regs.r11); puts("\n");
	puts("R12 "); puth64(regs.r12); puts("  R13 "); puth64(regs.r13); puts("  ");
	puts("R14 "); puth64(regs.r14); puts("  R15 "); puth64(regs.r15); puts("\n");
	// For interrupts 2 and 3, don't backtrace and error.
	// - 3 = breakpoint, 2 = ? (NMI?)
	if regs.intnum != 3 && regs.intnum != 2
	{
		let mut bp = regs.rbp;
		while let Some((newbp, ip)) = backtrace(bp)
		{
			puts(" > "); puth(ip);
			bp = newbp;
		}
		puts("\n");
		loop {}
	}
}

/// Obtain the old RBP value and return address from a provided RBP value
pub fn backtrace(bp: u64) -> Option<(u64,u64)>
{
	if bp == 0 {
		return None;
	}
	if bp % 8 != 0 {
		return None;
	}
	if ! ::memory::buf_valid(bp as *const (), 16) {
		return None;
	}

	// [rbp] = oldrbp, [rbp+8] = IP
	unsafe
	{
		let ptr: *const [u64; 2] = ::core::mem::transmute(bp);
		let newbp = (*ptr)[0];
		let newip = (*ptr)[1];
		// Check validity of output BP, must be > old BP (upwards on the stack)
		// - If not, return 0 (which will cause a break next loop)
		if newbp <= bp {
			Some( (0, newip) )
		}
		else {
			Some( (newbp, newip) )
		}
	}
}

fn get_cr2() -> u64
{
	// SAFE: Just reads CR2, no sideeffect
	unsafe {
		let cr2: u64;
		asm!("movq %cr2, $0" : "=r" (cr2));
		cr2
	}
}

#[derive(Debug,Copy,Clone)]
/// Error code for bind_isr
pub enum BindISRError
{
	Used,
}

pub use super::hw::apic::IRQHandle;
pub use super::hw::apic::register_irq as bind_gsi;

/// Bind a callback (and params) to an allocatable ISR
pub fn bind_isr(isr: u8, callback: ISRHandler, info: *const(), idx: usize) -> Result<ISRHandle,BindISRError>
{
	log_trace!("bind_isr(isr={},callback={:?},info={:?},idx={})",
		isr, callback as *const u8, info, idx);
	// TODO: Validate if the requested ISR slot is valid (i.e. it's one of the allocatable ones)
	// 1. Check that this ISR slot on this CPU isn't taken
	let mut _mh = s_irq_handlers_lock.lock();
	let h = &mut _mh[isr as usize];
	log_trace!("&h = {:p}", h);
	if h.handler.is_some()
	{
		Err( BindISRError::Used )
	}
	else
	{
		// 2. Assign
		*h = IRQHandlersEnt {
			handler: Some(callback),
			info: info,
			idx: idx,
			};
		Ok( ISRHandle {
			idx: isr as usize,
			} )
	}
}

pub fn bind_free_isr(callback: ISRHandler, info: *const(), idx: usize) -> Result<ISRHandle,BindISRError>
{
	log_trace!("bind_free_isr(callback={:?},info={:?},idx={})", callback as *const u8, info, idx);

	let mut lh = s_irq_handlers_lock.lock();
	for i in 32 .. lh.len()
	{
		if lh[i].handler.is_none() {
			log_trace!("- Using ISR {}", i);
			lh[i] = IRQHandlersEnt {
				handler: Some(callback),
				info: info,
				idx: idx,
				};
			return Ok( ISRHandle {
				idx: i,
				} )
		}
	}

	Err( BindISRError::Used )
}

impl ISRHandle
{
	/// Returns an unbound ISR handle (null)
	pub fn unbound() -> ISRHandle {
		ISRHandle {
			idx: !0,
		}
	}
	/// Returns the bound ISR index
	pub fn idx(&self) -> usize { self.idx }
}

impl ::core::ops::Drop for ISRHandle
{
	fn drop(&mut self)
	{
		if self.idx < 256
		{
			let mut mh = s_irq_handlers_lock.lock();
			let h = &mut mh[self.idx];
			h.handler = None;
		}
	}
}

// vim: ft=rust
<commit_msg>Kernel/AMD64 - Dump SP on a PF<commit_after>// "Tifflin" Kernel
// - By John Hodge (thePowersGang)
//
// Core/main.rs
//! Low-level interrupt handling and CPU error handling
use prelude::*;
use super::{puts,puth};
use super::log::puth64;

#[repr(C)]
//#[derive(Copy,Clone)]
/// Register state as saved by the error ISR handler
pub struct InterruptRegs
{
	//fs: u64,
	gs: u64,

	rax: u64, rcx: u64, rdx: u64, rbx: u64,
	/*no rsp*/rbp: u64, rsi: u64, rdi: u64,
	r8: u64,  r9: u64,  r10: u64, r11: u64,
	r12: u64, r13: u64, r14: u64, r15: u64,

	intnum: u64, errorcode: u64,
	rip: u64, cs: u64,
	rflags: u64, rsp: u64, ss: u64,
}

#[repr(C)]
/// A handler for an ISR
pub type ISRHandler = extern "C" fn(isrnum: usize,info:*const(),idx:usize);

struct IRQHandlersEnt
{
	handler: Option<ISRHandler>,
	info: *const(),
	idx: usize,
}
impl Copy for IRQHandlersEnt {}
impl Clone for IRQHandlersEnt { fn clone(&self)->Self { *self } }
unsafe impl Send for IRQHandlersEnt {}

#[derive(Default)]
/// A handle for a bound ISR, unbound on drop
pub struct ISRHandle
{
	idx: usize,
}

#[allow(non_upper_case_globals)]
static s_irq_handlers_lock: ::sync::Mutex<[IRQHandlersEnt; 256]> = ::sync::Mutex::new( [IRQHandlersEnt{
	handler: None,
	info: 0 as *const _,
	idx: 0
	}; 256] );

#[no_mangle]
#[doc(hidden)]
/// ISR handler called by assembly
pub extern "C" fn irq_handler(index: usize)
{
	let lh = s_irq_handlers_lock.lock();
	let ent = (*lh)[index];
	if let Some(h) = ent.handler {
		(h)(index, ent.info, ent.idx);
	}
}

#[no_mangle]
#[doc(hidden)]
/// Error handler called by assembly
pub extern "C" fn error_handler(regs: &InterruptRegs)
{
	match regs.intnum
	{
	13 => { puts("GPF ("); puth(regs.errorcode); puts(")\n"); },
	14 => {
		let cr2;
		// SAFE: Just reads CR2
		unsafe { asm!("mov %cr2, $0" : "=r" (cr2)) };
		puts("PF ("); puth(regs.errorcode); puts(") at "); puth(cr2 as u64); puts(" by "); puth(regs.rip); puts(" SP="); puth(regs.rsp); puts("\n");
		if ::arch::memory::virt::handle_page_fault(cr2, regs.errorcode as u32) {
			return ;
		}
		},
	_ => { puts("ERROR "); puth(regs.intnum); puts(" (code "); puth(regs.errorcode); puts(")\n"); },
	}
	puts("CS:RIP  = "); puth(regs.cs); puts(":"); puth(regs.rip); puts("\n");
	puts("SS:RSP  = "); puth(regs.ss); puts(":"); puth(regs.rsp); puts("\n");
	puts("CR2 = "); puth(get_cr2()); puts("\n");
	puts("RAX "); puth64(regs.rax); puts("  RCX "); puth64(regs.rcx); puts("  ");
	puts("RDX "); puth64(regs.rdx); puts("  RBX "); puth64(regs.rbx); puts("\n");
	puts("RSI "); puth64(regs.rsi); puts("  RDI "); puth64(regs.rdi); puts("  ");
	puts("RSP "); puth64(regs.rsp); puts("  RBP "); puth64(regs.rbp); puts("\n");
	puts("R8  "); puth64(regs.r8 ); puts("  R9  "); puth64(regs.r9 ); puts("  ");
	puts("R10 "); puth64(regs.r10); puts("  R11 "); puth64(regs.r11); puts("\n");
	puts("R12 "); puth64(regs.r12); puts("  R13 "); puth64(regs.r13); puts("  ");
	puts("R14 "); puth64(regs.r14); puts("  R15 "); puth64(regs.r15); puts("\n");
	// For interrupts 2 and 3, don't backtrace and error.
	// - 3 = breakpoint, 2 = ? (NMI?)
	if regs.intnum != 3 && regs.intnum != 2
	{
		let mut bp = regs.rbp;
		while let Some((newbp, ip)) = backtrace(bp)
		{
			puts(" > "); puth(ip);
			bp = newbp;
		}
		puts("\n");
		loop {}
	}
}

/// Obtain the old RBP value and return address from a provided RBP value
pub fn backtrace(bp: u64) -> Option<(u64,u64)>
{
	if bp == 0 {
		return None;
	}
	if bp % 8 != 0 {
		return None;
	}
	if ! ::memory::buf_valid(bp as *const (), 16) {
		return None;
	}

	// [rbp] = oldrbp, [rbp+8] = IP
	unsafe
	{
		let ptr: *const [u64; 2] = ::core::mem::transmute(bp);
		let newbp = (*ptr)[0];
		let newip = (*ptr)[1];
		// Check validity of output BP, must be > old BP (upwards on the stack)
		// - If not, return 0 (which will cause a break next loop)
		if newbp <= bp {
			Some( (0, newip) )
		}
		else {
			Some( (newbp, newip) )
		}
	}
}

fn get_cr2() -> u64
{
	// SAFE: Just reads CR2, no sideeffect
	unsafe {
		let cr2: u64;
		asm!("movq %cr2, $0" : "=r" (cr2));
		cr2
	}
}

#[derive(Debug,Copy,Clone)]
/// Error code for bind_isr
pub enum BindISRError
{
	Used,
}

pub use super::hw::apic::IRQHandle;
pub use super::hw::apic::register_irq as bind_gsi;

/// Bind a callback (and params) to an allocatable ISR
pub fn bind_isr(isr: u8, callback: ISRHandler, info: *const(), idx: usize) -> Result<ISRHandle,BindISRError>
{
	log_trace!("bind_isr(isr={},callback={:?},info={:?},idx={})",
		isr, callback as *const u8, info, idx);
	// TODO: Validate if the requested ISR slot is valid (i.e. it's one of the allocatable ones)
	// 1. Check that this ISR slot on this CPU isn't taken
	let mut _mh = s_irq_handlers_lock.lock();
	let h = &mut _mh[isr as usize];
	log_trace!("&h = {:p}", h);
	if h.handler.is_some()
	{
		Err( BindISRError::Used )
	}
	else
	{
		// 2. Assign
		*h = IRQHandlersEnt {
			handler: Some(callback),
			info: info,
			idx: idx,
			};
		Ok( ISRHandle {
			idx: isr as usize,
			} )
	}
}

pub fn bind_free_isr(callback: ISRHandler, info: *const(), idx: usize) -> Result<ISRHandle,BindISRError>
{
	log_trace!("bind_free_isr(callback={:?},info={:?},idx={})", callback as *const u8, info, idx);

	let mut lh = s_irq_handlers_lock.lock();
	for i in 32 .. lh.len()
	{
		if lh[i].handler.is_none() {
			log_trace!("- Using ISR {}", i);
			lh[i] = IRQHandlersEnt {
				handler: Some(callback),
				info: info,
				idx: idx,
				};
			return Ok( ISRHandle {
				idx: i,
				} )
		}
	}

	Err( BindISRError::Used )
}

impl ISRHandle
{
	/// Returns an unbound ISR handle (null)
	pub fn unbound() -> ISRHandle {
		ISRHandle {
			idx: !0,
		}
	}
	/// Returns the bound ISR index
	pub fn idx(&self) -> usize { self.idx }
}

impl ::core::ops::Drop for ISRHandle
{
	fn drop(&mut self)
	{
		if self.idx < 256
		{
			let mut mh = s_irq_handlers_lock.lock();
			let h = &mut mh[self.idx];
			h.handler = None;
		}
	}
}

// vim: ft=rust
<|endoftext|>


<commit_before>use std::io;

use super::{Numeric, SignedNumeric, BitQueueBE, BitQueueLE, BitQueue};

pub trait BitRead {
    /// Reads an unsigned value from the stream with
    /// the given number of bits.  This method assumes
    /// that the programmer is using an output type
    /// sufficiently large to hold those bits.
    fn read<U>(&mut self, bits: u32) -> Result<U, io::Error>
        where U: Numeric;

    /// Reads a twos-complement signed value from the stream with
    /// the given number of bits.  This method assumes
    /// that the programmer is using an output type
    /// sufficiently large to hold those bits.
    fn read_signed<S>(&mut self, bits: u32) -> Result<S, io::Error>
        where S: SignedNumeric;

    /// Skips the given number of bits in the stream.
    /// Since this method does not need an accumulator,
    /// it may be slightly faster than reading to an empty variable.
    fn skip(&mut self, bits: u32) -> Result<(), io::Error>;

    /// Completely fills the given buffer with whole bytes.
    /// If the stream is already byte-aligned, it will map
    /// to a faster read_exact call.  Otherwise it will read
    /// bytes individually in 8-bit increments.
    fn read_bytes(&mut self, buf: &mut [u8]) -> Result<(), io::Error>;

    /// Reads an unsigned unary value with a stop bit of 0.
    fn read_unary0(&mut self) -> Result<u32, io::Error>;

    /// Reads an unsigned unary value with a stop bit of 1.
    fn read_unary1(&mut self) -> Result<u32, io::Error>;

    /// Returns true if the stream is aligned at a whole byte.
    fn byte_aligned(&self) -> bool;

    /// Throws away all unread bit values until the next whole byte.
    fn byte_align(&mut self);

    /*FIXME - add support for reading Huffman codes*/
}

pub struct BitReaderBE<'a> {
    reader: &'a mut io::BufRead,
    bitqueue: BitQueueBE<u8>
}

impl<'a> BitReaderBE<'a> {
    pub fn new(reader: &mut io::BufRead) -> BitReaderBE {
        BitReaderBE{reader: reader, bitqueue: BitQueueBE::new()}
    }
}

impl<'a> BitRead for BitReaderBE<'a> {
    fn read<U>(&mut self, mut bits: u32) -> Result<U, io::Error>
        where U: Numeric {
        use std::cmp::min;
        let mut acc: BitQueueBE<U> = BitQueueBE::new();

        /*transfer un-processed bits from queue to accumulator*/
        let queue_len = self.bitqueue.len();
        if queue_len > 0 {
            let to_transfer = min(queue_len, bits);
            acc.push(to_transfer, U::from_u8(self.bitqueue.pop(to_transfer)));
            bits -= to_transfer;
        }

        read_aligned(&mut self.reader, bits / 8, &mut acc)
        .and_then(|()| read_unaligned(&mut self.reader,
                                      bits % 8,
                                      &mut acc,
                                      &mut self.bitqueue))
        .map(|()| acc.value())
    }

    fn read_signed<S>(&mut self, bits: u32) -> Result<S, io::Error>
        where S: SignedNumeric {
        debug_assert!(bits >= 1);
        let sign = self.read::<S>(1)?;
        let unsigned = self.read::<S>(bits - 1)?;
        Ok(if sign.is_zero() {unsigned} else{unsigned.as_negative(bits)})
    }

    fn skip(&mut self, bits: u32) -> Result<(), io::Error> {
        /*FIXME - optimize this*/
        self.read::<u32>(bits).map(|_| ())
    }

    fn read_bytes(&mut self, buf: &mut [u8]) -> Result<(), io::Error> {
        if self.byte_aligned() {
            self.reader.read_exact(buf)
        } else {
            for b in buf.iter_mut() {
                *b = self.read::<u8>(8)?;
            }
            Ok(())
        }
    }

    fn read_unary0(&mut self) -> Result<u32, io::Error> {
        /*FIXME - optimize this*/
        let mut acc = 0;
        while self.read::<u32>(1)? != 0 {
            acc += 1;
        }
        Ok(acc)
    }

    fn read_unary1(&mut self) -> Result<u32, io::Error> {
        /*FIXME - optimize this*/
        let mut acc = 0;
        while self.read::<u32>(1)? != 1 {
            acc += 1;
        }
        Ok(acc)
    }

    #[inline]
    fn byte_aligned(&self) -> bool {
        self.bitqueue.is_empty()
    }

    #[inline]
    fn byte_align(&mut self) {
        self.bitqueue.clear()
    }
}

pub struct BitReaderLE<'a> {
    reader: &'a mut io::BufRead,
    bitqueue: BitQueueLE<u8>
}

impl<'a> BitReaderLE<'a> {
    pub fn new(reader: &mut io::BufRead) -> BitReaderLE {
        BitReaderLE{reader: reader, bitqueue: BitQueueLE::new()}
    }
}

impl<'a> BitRead for BitReaderLE<'a> {
    fn read<U>(&mut self, mut bits: u32) -> Result<U, io::Error>
        where U: Numeric {
        use std::cmp::min;

        let mut acc: BitQueueLE<U> = BitQueueLE::new();

        /*transfer un-processed bits from queue to accumulator*/
        let queue_len = self.bitqueue.len();
        if queue_len > 0 {
            let to_transfer = min(queue_len, bits);
            acc.push(to_transfer, U::from_u8(self.bitqueue.pop(to_transfer)));
            bits -= to_transfer;
        }

        read_aligned(&mut self.reader, bits / 8, &mut acc)
        .and_then(|()| read_unaligned(&mut self.reader,
                                      bits % 8,
                                      &mut acc,
                                      &mut self.bitqueue))
        .map(|()| acc.value())
    }

    fn read_signed<S>(&mut self, bits: u32) -> Result<S, io::Error>
        where S: SignedNumeric {
        debug_assert!(bits >= 1);
        let unsigned = self.read::<S>(bits - 1)?;
        let sign = self.read::<S>(1)?;
        Ok(if sign.is_zero() {unsigned} else {unsigned.as_negative(bits)})
    }

    fn skip(&mut self, bits: u32) -> Result<(), io::Error> {
        /*FIXME - optimize this*/
        self.read::<u32>(bits).map(|_| ())
    }

    fn read_bytes(&mut self, buf: &mut [u8]) -> Result<(), io::Error> {
        if self.byte_aligned() {
            self.reader.read_exact(buf)
        } else {
            for b in buf.iter_mut() {
                *b = self.read::<u8>(8)?;
            }
            Ok(())
        }
    }

    fn read_unary0(&mut self) -> Result<u32, io::Error> {
        /*FIXME - optimize this*/
        let mut acc = 0;
        while self.read::<u32>(1)? != 0 {
            acc += 1;
        }
        Ok(acc)
    }

    fn read_unary1(&mut self) -> Result<u32, io::Error> {
        /*FIXME - optimize this*/
        let mut acc = 0;
        while self.read::<u32>(1)? != 1 {
            acc += 1;
        }
        Ok(acc)
    }

    #[inline]
    fn byte_aligned(&self) -> bool {
        self.bitqueue.is_empty()
    }

    #[inline]
    fn byte_align(&mut self) {
        self.bitqueue.clear()
    }
}

fn read_aligned<N>(reader: &mut io::BufRead,
                   mut bytes: u32,
                   acc: &mut BitQueue<N>) -> Result<(), io::Error>
    where N: Numeric {
    use std::cmp::min;

    while bytes > 0 {
        let processed = {
            let buf = reader.fill_buf()?;
            let to_process = min(bytes as usize, buf.len());
            for b in &buf[0..to_process] {
                acc.push(8, N::from_u8(*b));
            }
            to_process
        };
        if processed > 0 {
            reader.consume(processed);
            bytes -= processed as u32;
        } else {
            return Err(io::Error::new(
                io::ErrorKind::UnexpectedEof, "EOF in stream"));
        }
    }
    Ok(())
}

fn read_unaligned<N>(reader: &mut io::BufRead,
                     bits: u32,
                     acc: &mut BitQueue<N>,
                     rem: &mut BitQueue<u8>) -> Result<(), io::Error>
    where N: Numeric {

    debug_assert!(bits <= 8);

    if bits > 0 {
        let length = {
            let buf = reader.fill_buf()?;
            if buf.len() > 0 {
                rem.set(buf[0], 8);
                acc.push(bits, N::from_u8(rem.pop(bits)));
                1
            } else {0}
        };
        if length > 0 {
            Ok(reader.consume(length))
        } else {
            Err(io::Error::new(
                io::ErrorKind::UnexpectedEof, "EOF in stream"))
        }
    } else {
        Ok(())
    }
}
<commit_msg>Move read unary methods to common trait<commit_after>use std::io;

use super::{Numeric, SignedNumeric, BitQueueBE, BitQueueLE, BitQueue};

pub trait BitRead {
    /// Reads an unsigned value from the stream with
    /// the given number of bits.  This method assumes
    /// that the programmer is using an output type
    /// sufficiently large to hold those bits.
    fn read<U>(&mut self, bits: u32) -> Result<U, io::Error>
        where U: Numeric;

    /// Reads a twos-complement signed value from the stream with
    /// the given number of bits.  This method assumes
    /// that the programmer is using an output type
    /// sufficiently large to hold those bits.
    fn read_signed<S>(&mut self, bits: u32) -> Result<S, io::Error>
        where S: SignedNumeric;

    /// Skips the given number of bits in the stream.
    /// Since this method does not need an accumulator,
    /// it may be slightly faster than reading to an empty variable.
    fn skip(&mut self, bits: u32) -> Result<(), io::Error>;

    /// Completely fills the given buffer with whole bytes.
    /// If the stream is already byte-aligned, it will map
    /// to a faster read_exact call.  Otherwise it will read
    /// bytes individually in 8-bit increments.
    fn read_bytes(&mut self, buf: &mut [u8]) -> Result<(), io::Error>;

    /// Reads an unsigned unary value with a stop bit of 0.
    fn read_unary0(&mut self) -> Result<u32, io::Error> {
        /*FIXME - optimize this*/
        let mut acc = 0;
        while self.read::<u32>(1)? != 0 {
            acc += 1;
        }
        Ok(acc)
    }

    /// Reads an unsigned unary value with a stop bit of 1.
    fn read_unary1(&mut self) -> Result<u32, io::Error> {
        /*FIXME - optimize this*/
        let mut acc = 0;
        while self.read::<u32>(1)? != 1 {
            acc += 1;
        }
        Ok(acc)
    }

    /// Returns true if the stream is aligned at a whole byte.
    fn byte_aligned(&self) -> bool;

    /// Throws away all unread bit values until the next whole byte.
    fn byte_align(&mut self);

    /*FIXME - add support for reading Huffman codes*/
}

pub struct BitReaderBE<'a> {
    reader: &'a mut io::BufRead,
    bitqueue: BitQueueBE<u8>
}

impl<'a> BitReaderBE<'a> {
    pub fn new(reader: &mut io::BufRead) -> BitReaderBE {
        BitReaderBE{reader: reader, bitqueue: BitQueueBE::new()}
    }
}

impl<'a> BitRead for BitReaderBE<'a> {
    fn read<U>(&mut self, mut bits: u32) -> Result<U, io::Error>
        where U: Numeric {
        use std::cmp::min;
        let mut acc: BitQueueBE<U> = BitQueueBE::new();

        /*transfer un-processed bits from queue to accumulator*/
        let queue_len = self.bitqueue.len();
        if queue_len > 0 {
            let to_transfer = min(queue_len, bits);
            acc.push(to_transfer, U::from_u8(self.bitqueue.pop(to_transfer)));
            bits -= to_transfer;
        }

        read_aligned(&mut self.reader, bits / 8, &mut acc)
        .and_then(|()| read_unaligned(&mut self.reader,
                                      bits % 8,
                                      &mut acc,
                                      &mut self.bitqueue))
        .map(|()| acc.value())
    }

    fn read_signed<S>(&mut self, bits: u32) -> Result<S, io::Error>
        where S: SignedNumeric {
        debug_assert!(bits >= 1);
        let sign = self.read::<S>(1)?;
        let unsigned = self.read::<S>(bits - 1)?;
        Ok(if sign.is_zero() {unsigned} else{unsigned.as_negative(bits)})
    }

    fn skip(&mut self, bits: u32) -> Result<(), io::Error> {
        /*FIXME - optimize this*/
        self.read::<u32>(bits).map(|_| ())
    }

    fn read_bytes(&mut self, buf: &mut [u8]) -> Result<(), io::Error> {
        if self.byte_aligned() {
            self.reader.read_exact(buf)
        } else {
            for b in buf.iter_mut() {
                *b = self.read::<u8>(8)?;
            }
            Ok(())
        }
    }

    #[inline]
    fn byte_aligned(&self) -> bool {
        self.bitqueue.is_empty()
    }

    #[inline]
    fn byte_align(&mut self) {
        self.bitqueue.clear()
    }
}

pub struct BitReaderLE<'a> {
    reader: &'a mut io::BufRead,
    bitqueue: BitQueueLE<u8>
}

impl<'a> BitReaderLE<'a> {
    pub fn new(reader: &mut io::BufRead) -> BitReaderLE {
        BitReaderLE{reader: reader, bitqueue: BitQueueLE::new()}
    }
}

impl<'a> BitRead for BitReaderLE<'a> {
    fn read<U>(&mut self, mut bits: u32) -> Result<U, io::Error>
        where U: Numeric {
        use std::cmp::min;

        let mut acc: BitQueueLE<U> = BitQueueLE::new();

        /*transfer un-processed bits from queue to accumulator*/
        let queue_len = self.bitqueue.len();
        if queue_len > 0 {
            let to_transfer = min(queue_len, bits);
            acc.push(to_transfer, U::from_u8(self.bitqueue.pop(to_transfer)));
            bits -= to_transfer;
        }

        read_aligned(&mut self.reader, bits / 8, &mut acc)
        .and_then(|()| read_unaligned(&mut self.reader,
                                      bits % 8,
                                      &mut acc,
                                      &mut self.bitqueue))
        .map(|()| acc.value())
    }

    fn read_signed<S>(&mut self, bits: u32) -> Result<S, io::Error>
        where S: SignedNumeric {
        debug_assert!(bits >= 1);
        let unsigned = self.read::<S>(bits - 1)?;
        let sign = self.read::<S>(1)?;
        Ok(if sign.is_zero() {unsigned} else {unsigned.as_negative(bits)})
    }

    fn skip(&mut self, bits: u32) -> Result<(), io::Error> {
        /*FIXME - optimize this*/
        self.read::<u32>(bits).map(|_| ())
    }

    fn read_bytes(&mut self, buf: &mut [u8]) -> Result<(), io::Error> {
        if self.byte_aligned() {
            self.reader.read_exact(buf)
        } else {
            for b in buf.iter_mut() {
                *b = self.read::<u8>(8)?;
            }
            Ok(())
        }
    }

    #[inline]
    fn byte_aligned(&self) -> bool {
        self.bitqueue.is_empty()
    }

    #[inline]
    fn byte_align(&mut self) {
        self.bitqueue.clear()
    }
}

fn read_aligned<N>(reader: &mut io::BufRead,
                   mut bytes: u32,
                   acc: &mut BitQueue<N>) -> Result<(), io::Error>
    where N: Numeric {
    use std::cmp::min;

    while bytes > 0 {
        let processed = {
            let buf = reader.fill_buf()?;
            let to_process = min(bytes as usize, buf.len());
            for b in &buf[0..to_process] {
                acc.push(8, N::from_u8(*b));
            }
            to_process
        };
        if processed > 0 {
            reader.consume(processed);
            bytes -= processed as u32;
        } else {
            return Err(io::Error::new(
                io::ErrorKind::UnexpectedEof, "EOF in stream"));
        }
    }
    Ok(())
}

fn read_unaligned<N>(reader: &mut io::BufRead,
                     bits: u32,
                     acc: &mut BitQueue<N>,
                     rem: &mut BitQueue<u8>) -> Result<(), io::Error>
    where N: Numeric {

    debug_assert!(bits <= 8);

    if bits > 0 {
        let length = {
            let buf = reader.fill_buf()?;
            if buf.len() > 0 {
                rem.set(buf[0], 8);
                acc.push(bits, N::from_u8(rem.pop(bits)));
                1
            } else {0}
        };
        if length > 0 {
            Ok(reader.consume(length))
        } else {
            Err(io::Error::new(
                io::ErrorKind::UnexpectedEof, "EOF in stream"))
        }
    } else {
        Ok(())
    }
}
<|endoftext|>


<commit_before>use std::io::fs;
use std::path::posix::Path;
use std::os::homedir;
#[cfg(test)] use test_helper::{cleanup_dir,random_name};

static MUXED_NAME_STR: &'static str = "muxed";

/// Create the muxed directory and return the path if creation is successful.
pub fn create_muxed_dir(name: &Path) -> Path {
    match fs::mkdir(path, ::std::io::UserRWX) {
        Ok(()) => (),
        Err(_e) => println!("Failed to create muxed directory: {}", path.filename())
    }

    path.clone()
}

/// Return the users current homedir as a string.
pub fn homedir_string() -> String {
    let home_unwrap = homedir().unwrap();
    format!("{}", home_unwrap.display())
}

pub fn muxed_dir() -> Path {
    match MUXED_DIR.exists() {
        true  => MUXED_DIR,
        false => create_muxed_dir(MUXED_DIR)
    }
}

#[test]
fn muxed_dir_exists_returns_false() {
    assert!(!muxed_dir_exists(&random_name()));
}

#[test]
fn muxed_dir_exists_returns_true() {
    let dir = random_name();
    create_muxed_dir(&dir);
    assert!(muxed_dir_exists(&dir));

    let muxed_path  = &Path::new(format!("{}/.{}/", homedir_string(), dir));
    cleanup_dir(muxed_path);
}

#[test]
fn creates_muxed_dir() {
    let dir = random_name();
    let muxed_path  = &Path::new(format!("{}/.{}/", homedir_string(), dir));
    create_muxed_dir(&dir);
    assert!(muxed_path.exists());
    cleanup_dir(muxed_path);
}
<commit_msg>Usse the muxed_path() function instead of the static method.<commit_after>use std::io::fs;
use std::path::posix::Path;
use std::os::homedir;
#[cfg(test)] use test_helper::{cleanup_dir,random_name};

static MUXED_NAME_STR: &'static str = "muxed";

/// Create the muxed directory and return the path if creation is successful.
pub fn create_muxed_dir(name: &Path) -> Path {
    match fs::mkdir(path, ::std::io::UserRWX) {
        Ok(()) => (),
        Err(_e) => println!("Failed to create muxed directory: {}", path.filename())
    }

    path.clone()
}

/// Return the users current homedir as a string.
pub fn homedir_string() -> String {
    let home_unwrap = homedir().unwrap();
    format!("{}", home_unwrap.display())
}

pub fn muxed_dir() -> Path {
    let path = muxed_path();
    match path.exists() {
        true  => path,
        false => create_muxed_dir(&path)
    }
}

#[test]
fn muxed_dir_exists_returns_false() {
    assert!(!muxed_dir_exists(&random_name()));
}

#[test]
fn muxed_dir_exists_returns_true() {
    let dir = random_name();
    create_muxed_dir(&dir);
    assert!(muxed_dir_exists(&dir));

    let muxed_path  = &Path::new(format!("{}/.{}/", homedir_string(), dir));
    cleanup_dir(muxed_path);
}

#[test]
fn creates_muxed_dir() {
    let dir = random_name();
    let muxed_path  = &Path::new(format!("{}/.{}/", homedir_string(), dir));
    create_muxed_dir(&dir);
    assert!(muxed_path.exists());
    cleanup_dir(muxed_path);
}
<|endoftext|>


<commit_before>use testsyn::{parse_str, Item};

use json_typegen_shared::{codegen, ImportStyle, Options};

/// Function to test AST equality, not string equality
fn code_output_test(name: &str, input: &str, expected: &str) {
    let mut options = Options::default();
    options.import_style = ImportStyle::AssumeExisting;
    let res = codegen(name, input, options);
    let output = res.unwrap();
    assert_eq!(
        // Wrapping in mod Foo { } since there is no impl Parse for Vec<Item>
        parse_str::<Item>(&format!("mod Foo {{ {} }}", &output)).unwrap(),
        parse_str::<Item>(&format!("mod Foo {{ {} }}", expected)).unwrap(),
        "\n\nUnexpected output code:\n  input: {}\n  output:\n{}\n  expected: {}",
        input,
        output,
        expected
    );
}

#[test]
fn empty_object() {
    code_output_test(
        "Root",
        r##"
            {}
        "##,
        r##"
            #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
            pub struct Root {}
        "##,
    );
}

#[test]
fn list_of_numbers() {
    code_output_test(
        "Numbers",
        r##"
            [1, 2, 3]
        "##,
        r##"
            pub type Numbers = Vec<i64>;
        "##,
    );
}

#[test]
fn point() {
    code_output_test(
        "Point",
        r##"
            {
                "x": 2,
                "y": 3
            }
        "##,
        r##"
            #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
            pub struct Point {
                pub x: i64,
                pub y: i64,
            }
        "##,
    );
}

#[test]
fn pub_crate_point() {
    code_output_test(
        "pub(crate) Point",
        r##"
            {
                "x": 2,
                "y": 3
            }
        "##,
        r##"
            #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
            pub(crate) struct Point {
                pub x: i64,
                pub y: i64,
            }
        "##,
    );
}

#[test]
fn optionals() {
    code_output_test(
        "Optionals",
        r##"
            [
                {
                    "in_both": 5,
                    "missing": 5,
                    "has_null": 5
                },
                {
                    "in_both": 5,
                    "has_null": null,
                    "added": 5
                }
            ]
        "##,
        r##"
            pub type Optionals = Vec<Optional>;

            #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
            pub struct Optional {
                pub in_both: i64,
                pub missing: Option<i64>,
                pub has_null: Option<i64>,
                pub added: Option<i64>,
            }
        "##,
    );
}

#[test]
fn fallback() {
    code_output_test(
        "FallbackExamples",
        r##"
            [
                {
                    "only_null": null,
                    "conflicting": 5,
                    "empty_array": []
                },
                {
                    "only_null": null,
                    "conflicting": "five",
                    "empty_array": []
                }
            ]
        "##,
        r##"
            pub type FallbackExamples = Vec<FallbackExample>;

            #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
            pub struct FallbackExample {
                pub only_null: Value,
                pub conflicting: Value,
                pub empty_array: Vec<Value>,
            }
        "##,
    );
}

#[test]
fn nesting() {
    code_output_test(
        "NestedTypes",
        r##"
            [
                {
                    "nested": {
                        "a": 5,
                        "doubly_nested": { "c": 10 }
                    },
                    "in_array": [{ "b": 5 }]
                }
            ]
        "##,
        r##"
            pub type NestedTypes = Vec<NestedType>;

            #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
            pub struct NestedType {
                pub nested: Nested,
                pub in_array: Vec<InArray>,
            }

            #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
            pub struct Nested {
                pub a: i64,
                pub doubly_nested: DoublyNested,
            }

            #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
            pub struct DoublyNested {
                pub c: i64,
            }

            #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
            pub struct InArray {
                pub b: i64,
            }
        "##,
    );
}

#[test]
fn tuple() {
    code_output_test(
        "Pagination",
        r##"
            [
                {
                    "pages": 1,
                    "items": 3
                },
                [
                    {
                        "name": "John"
                    },
                    {
                        "name": "James"
                    },
                    {
                        "name": "Jake"
                    }
                ]
            ]
        "##,
        r##"
            pub type Pagination = (Pagination2, Vec<Pagination3>);

            #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
            pub struct Pagination2 {
                pub pages: i64,
                pub items: i64,
            }

            #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
            pub struct Pagination3 {
                pub name : String,
            }
        "##,
    );
}

#[test]
fn rename() {
    code_output_test(
        "Renamed",
        r##"
            {
                "type": 5
            }
        "##,
        r##"
            #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
            pub struct Renamed {
                #[serde(rename = "type")]
                pub type_field: i64,
            }
        "##,
    );
}
<commit_msg>Annotate test input for syntax highlighting<commit_after>use testsyn::{parse_str, Item};

use json_typegen_shared::{codegen, ImportStyle, Options};

/// Function to test AST equality, not string equality
fn code_output_test(name: &str, input: &str, expected: &str) {
    let mut options = Options::default();
    options.import_style = ImportStyle::AssumeExisting;
    let res = codegen(name, input, options);
    let output = res.unwrap();
    assert_eq!(
        // Wrapping in mod Foo { } since there is no impl Parse for Vec<Item>
        parse_str::<Item>(&format!("mod Foo {{ {} }}", &output)).unwrap(),
        parse_str::<Item>(&format!("mod Foo {{ {} }}", expected)).unwrap(),
        "\n\nUnexpected output code:\n  input: {}\n  output:\n{}\n  expected: {}",
        input,
        output,
        expected
    );
}

#[test]
fn empty_object() {
    code_output_test(
        "Root",
        // language=JSON
        r##"
            {}
        "##,
        // language=Rust
        r##"
            #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
            pub struct Root {}
        "##,
    );
}

#[test]
fn list_of_numbers() {
    code_output_test(
        "Numbers",
        // language=JSON
        r##"
            [1, 2, 3]
        "##,
        // language=Rust
        r##"
            pub type Numbers = Vec<i64>;
        "##,
    );
}

#[test]
fn point() {
    code_output_test(
        "Point",
        // language=JSON
        r##"
            {
                "x": 2,
                "y": 3
            }
        "##,
        // language=Rust
        r##"
            #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
            pub struct Point {
                pub x: i64,
                pub y: i64,
            }
        "##,
    );
}

#[test]
fn pub_crate_point() {
    code_output_test(
        "pub(crate) Point",
        // language=JSON
        r##"
            {
                "x": 2,
                "y": 3
            }
        "##,
        // language=Rust
        r##"
            #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
            pub(crate) struct Point {
                pub x: i64,
                pub y: i64,
            }
        "##,
    );
}

#[test]
fn optionals() {
    code_output_test(
        "Optionals",
        // language=JSON
        r##"
            [
                {
                    "in_both": 5,
                    "missing": 5,
                    "has_null": 5
                },
                {
                    "in_both": 5,
                    "has_null": null,
                    "added": 5
                }
            ]
        "##,
        // language=Rust
        r##"
            pub type Optionals = Vec<Optional>;

            #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
            pub struct Optional {
                pub in_both: i64,
                pub missing: Option<i64>,
                pub has_null: Option<i64>,
                pub added: Option<i64>,
            }
        "##,
    );
}

#[test]
fn fallback() {
    code_output_test(
        "FallbackExamples",
        // language=JSON
        r##"
            [
                {
                    "only_null": null,
                    "conflicting": 5,
                    "empty_array": []
                },
                {
                    "only_null": null,
                    "conflicting": "five",
                    "empty_array": []
                }
            ]
        "##,
        // language=Rust
        r##"
            pub type FallbackExamples = Vec<FallbackExample>;

            #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
            pub struct FallbackExample {
                pub only_null: Value,
                pub conflicting: Value,
                pub empty_array: Vec<Value>,
            }
        "##,
    );
}

#[test]
fn nesting() {
    code_output_test(
        "NestedTypes",
        // language=JSON
        r##"
            [
                {
                    "nested": {
                        "a": 5,
                        "doubly_nested": { "c": 10 }
                    },
                    "in_array": [{ "b": 5 }]
                }
            ]
        "##,
        // language=Rust
        r##"
            pub type NestedTypes = Vec<NestedType>;

            #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
            pub struct NestedType {
                pub nested: Nested,
                pub in_array: Vec<InArray>,
            }

            #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
            pub struct Nested {
                pub a: i64,
                pub doubly_nested: DoublyNested,
            }

            #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
            pub struct DoublyNested {
                pub c: i64,
            }

            #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
            pub struct InArray {
                pub b: i64,
            }
        "##,
    );
}

#[test]
fn tuple() {
    code_output_test(
        "Pagination",
        // language=JSON
        r##"
            [
                {
                    "pages": 1,
                    "items": 3
                },
                [
                    {
                        "name": "John"
                    },
                    {
                        "name": "James"
                    },
                    {
                        "name": "Jake"
                    }
                ]
            ]
        "##,
        // language=Rust
        r##"
            pub type Pagination = (Pagination2, Vec<Pagination3>);

            #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
            pub struct Pagination2 {
                pub pages: i64,
                pub items: i64,
            }

            #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
            pub struct Pagination3 {
                pub name : String,
            }
        "##,
    );
}

#[test]
fn rename() {
    code_output_test(
        "Renamed",
        // language=JSON
        r##"
            {
                "type": 5
            }
        "##,
        // language=Rust
        r##"
            #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
            pub struct Renamed {
                #[serde(rename = "type")]
                pub type_field: i64,
            }
        "##,
    );
}
<|endoftext|>


<commit_before>use std::mem;

use runtime::{Class, Method, Object, Sel, self};
use {encode, Encode};

/*
 The Sized bound on Message is unfortunate; ideally, objc objects would not be
 treated as Sized. However, rust won't allow casting a dynamically-sized type
 pointer to an Object pointer, because dynamically-sized types can have fat
 pointers (two words) instead of real pointers.
 */
/// Types that may be sent Objective-C messages.
/// For example: objects, classes, and blocks.
pub unsafe trait Message: Sized { }

unsafe impl Message for Object { }

unsafe impl Message for Class { }

/// A trait for converting to a pointer to a type that may be sent Objective-C
/// messages.
pub trait ToMessage {
    type Target: Message;

    fn as_ptr(&self) -> *mut Self::Target;

    fn is_nil(&self) -> bool {
        self.as_ptr().is_null()
    }
}

impl<T> ToMessage for *const T where T: Message {
    type Target = T;

    fn as_ptr(&self) -> *mut T {
        *self as *mut T
    }
}

impl<T> ToMessage for *mut T where T: Message {
    type Target = T;

    fn as_ptr(&self) -> *mut T {
        *self
    }
}

impl<'a, T> ToMessage for &'a T where T: Message {
    type Target = T;

    fn as_ptr(&self) -> *mut T {
        *self as *const T as *mut T
    }
}

impl<'a, T> ToMessage for &'a mut T where T: Message {
    type Target = T;

    fn as_ptr(&self) -> *mut T {
        *self
    }
}

fn msg_send_fn<R>() -> unsafe extern fn(*mut Object, Sel, ...) -> R {
    unsafe {
        mem::transmute(runtime::objc_msgSend)
    }
}

pub trait MessageArguments {
    unsafe fn send<T, R>(self, obj: &T, sel: Sel) -> R where T: ToMessage;
}

macro_rules! message_args_impl {
    ($($a:ident : $t:ident),*) => (
        impl<$($t),*> MessageArguments for ($($t,)*) {
            unsafe fn send<T, R>(self, obj: &T, sel: Sel) -> R where T: ToMessage {
                let msg_send_fn = msg_send_fn::<R>();
                let msg_send_fn: unsafe extern fn(*mut Object, Sel $(, $t)*) -> R =
                    mem::transmute(msg_send_fn);
                let obj_ptr = obj.as_ptr() as *mut Object;
                let ($($a,)*) = self;
                msg_send_fn(obj_ptr, sel $(, $a)*)
            }
        }
    );
}

message_args_impl!();
message_args_impl!(a: A);
message_args_impl!(a: A, b: B);
message_args_impl!(a: A, b: B, c: C);
message_args_impl!(a: A, b: B, c: C, d: D);
message_args_impl!(a: A, b: B, c: C, d: D, e: E);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L);

#[allow(dead_code)]
fn verify_message_arguments(types: &[&str], method: &Method) -> Result<(), String> {
    let count = 2 + types.len();
    let expected_count = method.arguments_count();
    if count != expected_count {
        return Err(format!("Method {:?} accepts {} arguments, but {} were given",
            method.name(), expected_count, count));
    }

    let expected_types = (2..expected_count).map(|i| method.argument_type(i));
    for (&arg, expected) in types.iter().zip(expected_types) {
        let expected = match expected {
            Some(s) => s,
            None => return Err(format!("Method {:?} doesn't expect argument with type code {}",
                method.name(), arg)),
        };
        if arg != &*expected {
            return Err(format!("Method {:?} expected argument with type code {} but was given {}",
                method.name(), &*expected, arg));
        }
    }

    Ok(())
}

fn verify_message_signature<T, A, R>(obj: Option<&T>, sel: Sel, _args: &A) ->
        Result<(), String> where T: Message, A: MessageArguments, R: Encode {
    let obj = match obj {
        Some(obj) => obj,
        None => return Err(format!("Messaging {:?} to nil", sel)),
    };
    let cls = unsafe {
        let obj = &*(obj as *const _ as *const Object);
        obj.class()
    };
    let method = match cls.instance_method(sel) {
        Some(method) => method,
        None => return Err(format!("Method {:?} not found on class {:?}",
            sel, cls)),
    };

    let ret = encode::<R>();
    let expected_ret = method.return_type();
    // Allow encoding "oneway void" (Vv) as "void" (v)
    if &*expected_ret != ret && !(&*expected_ret == "Vv" && ret == "v") {
        return Err(format!("Return type code {} does not match expected {} for method {:?} on class {:?}",
            ret, &*expected_ret, sel, cls));
    }

    // I don't think either of these can happen, but just to be safe...
    let accepts_self_arg = match method.argument_type(0) {
        Some(s) => &*s == "@",
        None => false,
    };
    if !accepts_self_arg {
        return Err(format!("Method {:?} of class {:?} doesn't accept an argument for self",
            sel, cls));
    }
    let accepts_cmd_arg = match method.argument_type(1) {
        Some(s) => &*s == ":",
        None => false,
    };
    if !accepts_cmd_arg {
        return Err(format!("Method {:?} of class {:?} doesn't accept an argument for the selector",
            sel, cls));
    }

    Ok(())
}

pub unsafe fn send_message<T, A, R>(obj: &T, sel: Sel, args: A) -> R
        where T: ToMessage, A: MessageArguments {
    args.send(obj, sel)
}

pub unsafe fn send_message_verified<T, A, R>(obj: &T, sel: Sel, args: A) ->
        Result<R, String> where T: ToMessage, A: MessageArguments, R: Encode {
    let obj_ref = obj.as_ptr().as_ref();
    verify_message_signature::<_, _, R>(obj_ref, sel, &args).and_then(
        move |()| Ok(args.send(obj, sel)))
}
<commit_msg>Added a test for send_message.<commit_after>use std::mem;

use runtime::{Class, Method, Object, Sel, self};
use {encode, Encode};

/*
 The Sized bound on Message is unfortunate; ideally, objc objects would not be
 treated as Sized. However, rust won't allow casting a dynamically-sized type
 pointer to an Object pointer, because dynamically-sized types can have fat
 pointers (two words) instead of real pointers.
 */
/// Types that may be sent Objective-C messages.
/// For example: objects, classes, and blocks.
pub unsafe trait Message: Sized { }

unsafe impl Message for Object { }

unsafe impl Message for Class { }

/// A trait for converting to a pointer to a type that may be sent Objective-C
/// messages.
pub trait ToMessage {
    type Target: Message;

    fn as_ptr(&self) -> *mut Self::Target;

    fn is_nil(&self) -> bool {
        self.as_ptr().is_null()
    }
}

impl<T> ToMessage for *const T where T: Message {
    type Target = T;

    fn as_ptr(&self) -> *mut T {
        *self as *mut T
    }
}

impl<T> ToMessage for *mut T where T: Message {
    type Target = T;

    fn as_ptr(&self) -> *mut T {
        *self
    }
}

impl<'a, T> ToMessage for &'a T where T: Message {
    type Target = T;

    fn as_ptr(&self) -> *mut T {
        *self as *const T as *mut T
    }
}

impl<'a, T> ToMessage for &'a mut T where T: Message {
    type Target = T;

    fn as_ptr(&self) -> *mut T {
        *self
    }
}

fn msg_send_fn<R>() -> unsafe extern fn(*mut Object, Sel, ...) -> R {
    unsafe {
        mem::transmute(runtime::objc_msgSend)
    }
}

pub trait MessageArguments {
    unsafe fn send<T, R>(self, obj: &T, sel: Sel) -> R where T: ToMessage;
}

macro_rules! message_args_impl {
    ($($a:ident : $t:ident),*) => (
        impl<$($t),*> MessageArguments for ($($t,)*) {
            unsafe fn send<T, R>(self, obj: &T, sel: Sel) -> R where T: ToMessage {
                let msg_send_fn = msg_send_fn::<R>();
                let msg_send_fn: unsafe extern fn(*mut Object, Sel $(, $t)*) -> R =
                    mem::transmute(msg_send_fn);
                let obj_ptr = obj.as_ptr() as *mut Object;
                let ($($a,)*) = self;
                msg_send_fn(obj_ptr, sel $(, $a)*)
            }
        }
    );
}

message_args_impl!();
message_args_impl!(a: A);
message_args_impl!(a: A, b: B);
message_args_impl!(a: A, b: B, c: C);
message_args_impl!(a: A, b: B, c: C, d: D);
message_args_impl!(a: A, b: B, c: C, d: D, e: E);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L);

#[allow(dead_code)]
fn verify_message_arguments(types: &[&str], method: &Method) -> Result<(), String> {
    let count = 2 + types.len();
    let expected_count = method.arguments_count();
    if count != expected_count {
        return Err(format!("Method {:?} accepts {} arguments, but {} were given",
            method.name(), expected_count, count));
    }

    let expected_types = (2..expected_count).map(|i| method.argument_type(i));
    for (&arg, expected) in types.iter().zip(expected_types) {
        let expected = match expected {
            Some(s) => s,
            None => return Err(format!("Method {:?} doesn't expect argument with type code {}",
                method.name(), arg)),
        };
        if arg != &*expected {
            return Err(format!("Method {:?} expected argument with type code {} but was given {}",
                method.name(), &*expected, arg));
        }
    }

    Ok(())
}

fn verify_message_signature<T, A, R>(obj: Option<&T>, sel: Sel, _args: &A) ->
        Result<(), String> where T: Message, A: MessageArguments, R: Encode {
    let obj = match obj {
        Some(obj) => obj,
        None => return Err(format!("Messaging {:?} to nil", sel)),
    };
    let cls = unsafe {
        let obj = &*(obj as *const _ as *const Object);
        obj.class()
    };
    let method = match cls.instance_method(sel) {
        Some(method) => method,
        None => return Err(format!("Method {:?} not found on class {:?}",
            sel, cls)),
    };

    let ret = encode::<R>();
    let expected_ret = method.return_type();
    // Allow encoding "oneway void" (Vv) as "void" (v)
    if &*expected_ret != ret && !(&*expected_ret == "Vv" && ret == "v") {
        return Err(format!("Return type code {} does not match expected {} for method {:?} on class {:?}",
            ret, &*expected_ret, sel, cls));
    }

    // I don't think either of these can happen, but just to be safe...
    let accepts_self_arg = match method.argument_type(0) {
        Some(s) => &*s == "@",
        None => false,
    };
    if !accepts_self_arg {
        return Err(format!("Method {:?} of class {:?} doesn't accept an argument for self",
            sel, cls));
    }
    let accepts_cmd_arg = match method.argument_type(1) {
        Some(s) => &*s == ":",
        None => false,
    };
    if !accepts_cmd_arg {
        return Err(format!("Method {:?} of class {:?} doesn't accept an argument for the selector",
            sel, cls));
    }

    Ok(())
}

pub unsafe fn send_message<T, A, R>(obj: &T, sel: Sel, args: A) -> R
        where T: ToMessage, A: MessageArguments {
    args.send(obj, sel)
}

pub unsafe fn send_message_verified<T, A, R>(obj: &T, sel: Sel, args: A) ->
        Result<R, String> where T: ToMessage, A: MessageArguments, R: Encode {
    let obj_ref = obj.as_ptr().as_ref();
    verify_message_signature::<_, _, R>(obj_ref, sel, &args).and_then(
        move |()| Ok(args.send(obj, sel)))
}

#[cfg(test)]
mod tests {
    use runtime::Object;
    use test_utils;
    use super::send_message;

    #[test]
    fn test_send_message() {
        let obj = test_utils::sample_object();
        let result: *const Object = unsafe {
            send_message(&obj, sel!(self), ())
        };
        assert!(&*obj as *const Object == result);
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2017 Boucher, Antoni <bouanto@zoho.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

/*
 * TODO: automatically add the model() method with a () return type when it is not found?
 * FIXME: Doing model.text.push_str() will not cause a set_text() to be added.
 * TODO: think about conditions and loops (widget-list).
 */

#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate quote;
extern crate syn;

mod adder;
mod gen;
mod parser;
mod walker;

use std::collections::{HashMap, HashSet};
use std::sync::Mutex;

use adder::{Adder, Property};
use gen::gen;
use parser::Widget::{Gtk, Relm};
use parser::{Widget, parse};
use quote::{Tokens, ToTokens};
use syn::{Delimited, FunctionRetTy, Ident, ImplItem, Mac, MethodSig, TokenTree, parse_expr, parse_item};
use syn::FnArg::Captured;
use syn::fold::Folder;
use syn::ImplItemKind::{Const, Macro, Method, Type};
use syn::ItemKind::Impl;
use syn::Ty;
use syn::visit::Visitor;
use walker::ModelVariableVisitor;

type PropertyModelMap = HashMap<Ident, HashSet<Property>>;

struct Component {
    model_type: Ty,
    msg_type: Ty,
    view_type: Ident,
}

lazy_static! {
    static ref COMPONENTS: Mutex<HashMap<Ident, Component>> = Mutex::new(HashMap::new());
}

#[derive(Debug)]
struct State {
    container_method: Option<ImplItem>,
    container_type: Option<ImplItem>,
    model_type: Option<ImplItem>,
    msg_type: Option<Ty>,
    properties_model_map: Option<PropertyModelMap>,
    root_widget: Option<Ident>,
    root_widget_type: Option<Ident>,
    update_method: Option<ImplItem>,
    view_macro: Option<Mac>,
    widget_model_type: Option<Ty>,
    widgets: HashMap<Ident, Ident>, // Map widget ident to widget type.
}

impl State {
    fn new() -> Self {
        State {
            container_method: None,
            container_type: None,
            model_type: None,
            msg_type: None,
            properties_model_map: None,
            root_widget: None,
            root_widget_type: None,
            update_method: None,
            view_macro: None,
            widget_model_type: None,
            widgets: HashMap::new(),
        }
    }
}

pub fn gen_widget(input: Tokens) -> Tokens {
    let source = input.to_string();
    let mut ast = parse_item(&source).unwrap();
    if let Impl(unsafety, polarity, generics, path, typ, items) = ast.node {
        let name = get_name(&typ);
        let mut new_items = vec![];
        let mut state = State::new();
        for item in items {
            let i = item.clone();
            match item.node {
                Const(_, _) => panic!("Unexpected const item"),
                Macro(mac) => state.view_macro = Some(mac),
                Method(sig, _) => {
                    match item.ident.to_string().as_ref() {
                        "container" => state.container_method = Some(i),
                        "model" => {
                            state.widget_model_type = Some(get_return_type(sig));
                            new_items.push(i);
                        },
                        "subscriptions" | "update_command" => new_items.push(i),
                        "update" => {
                            state.msg_type = Some(get_second_param_type(&sig));
                            state.update_method = Some(i)
                        },
                        method_name => panic!("Unexpected method {}", method_name),
                    }
                },
                Type(_) => {
                    if item.ident == Ident::new("Container") {
                        state.container_type = Some(i);
                    }
                    else if item.ident == Ident::new("Model") {
                        state.model_type = Some(i);
                    }
                    else {
                        panic!("Unexpected type item {:?}", item.ident);
                    }
                },
            }
        }
        let (view, map, relm_widgets) = get_view(&name, &mut state);
        state.properties_model_map = Some(map);
        new_items.push(view);
        state.widgets.insert(state.root_widget.clone().expect("root widget"),
            state.root_widget_type.clone().expect("root widget type"));
        new_items.push(get_model_type(state.model_type, state.widget_model_type));
        new_items.push(get_container_type(state.container_type, state.root_widget_type));
        new_items.push(get_update(state.update_method.expect("update method"),
            &state.properties_model_map.expect("properties model map")));
        new_items.push(get_container(state.container_method, state.root_widget));
        let item = Impl(unsafety, polarity, generics, path, typ, new_items);
        ast.node = item;
        let widget_struct = create_struct(&name, &state.widgets, &relm_widgets);
        quote! {
            #widget_struct
            #ast
        }
    }
    else {
        panic!("Expected impl");
    }
}

fn add_widgets(widget: &Widget, widgets: &mut HashMap<Ident, Ident>, map: &PropertyModelMap) {
    // Only add widgets that are needed by the update() function.
    let mut to_add = false;
    for values in map.values() {
        for value in values {
            if value.widget_name == widget.name() {
                to_add = true;
            }
        }
    }
    if to_add {
        widgets.insert(widget.name().clone(), widget.typ().clone());
    }
    match *widget {
        Gtk(ref widget) =>  {
            for child in &widget.children {
                add_widgets(child, widgets, map);
            }
        },
        Relm(ref widget) =>  {
            for child in &widget.children {
                add_widgets(child, widgets, map);
            }
        },
    }
}

fn block_to_impl_item(tokens: Tokens) -> ImplItem {
    let implementation = quote! {
        impl Test {
            #tokens
        }
    };
    let implementation = parse_item(implementation.as_str()).unwrap();
    match implementation.node {
        Impl(_, _, _, _, _, items) => items[0].clone(),
        _ => unreachable!(),
    }
}

fn create_struct(name: &Ident, widgets: &HashMap<Ident, Ident>, relm_widgets: &HashMap<Ident, Ident>) -> Tokens {
    let widgets = widgets.iter().filter(|&(ident, _)| !relm_widgets.contains_key(ident));
    let (idents, types): (Vec<_>, Vec<_>) = widgets.unzip();
    let relm_idents = relm_widgets.keys();
    let relm_types = relm_widgets.values();
    quote! {
        #[allow(dead_code)]
        #[derive(Clone)]
        pub struct #name {
            #(#idents: #types,)*
            #(#relm_idents: #relm_types,)*
        }
    }
}

fn get_container(container_method: Option<ImplItem>, root_widget: Option<Ident>) -> ImplItem {
    container_method.unwrap_or_else(|| {
        let root_widget = root_widget.expect("root widget");
        block_to_impl_item(quote! {
            fn container(&self) -> &Self::Container {
                &self.#root_widget
            }
        })
    })
}

fn get_container_type(container_type: Option<ImplItem>, root_widget_type: Option<Ident>) -> ImplItem {
    container_type.unwrap_or_else(|| {
        let root_widget_type = root_widget_type.expect("root widget type");
        block_to_impl_item(quote! {
            type Container = #root_widget_type;
        })
    })
}

fn get_model_type(model_type: Option<ImplItem>, widget_model_type: Option<Ty>) -> ImplItem {
    model_type.unwrap_or_else(|| {
        let widget_model_type = widget_model_type.expect("widget model type");
        block_to_impl_item(quote! {
            type Model = #widget_model_type;
        })
    })
}

fn get_name(typ: &Ty) -> Ident {
    if let Ty::Path(_, ref path) = *typ {
        let mut tokens = Tokens::new();
        path.to_tokens(&mut tokens);
        Ident::new(tokens.to_string())
    }
    else {
        panic!("Expected Path")
    }
}

macro_rules! get_map {
    ($widget:expr, $map:expr) => {{
        for child in &$widget.children {
            get_properties_model_map(child, $map);
        }
    }};
}

/*
 * The map maps model variable name to a vector of tuples (widget name, property name).
 */
fn get_properties_model_map(widget: &Widget, map: &mut PropertyModelMap) {
    match *widget {
        Gtk(ref widget) => {
            for (name, value) in &widget.properties {
                let string = value.parse::<String>().unwrap();
                let expr = parse_expr(&string).unwrap();
                let mut visitor = ModelVariableVisitor::new();
                visitor.visit_expr(&expr);
                let model_variables = visitor.idents;
                for var in model_variables {
                    let set = map.entry(var).or_insert_with(HashSet::new);
                    set.insert(Property {
                        expr: string.clone(),
                        name: name.clone(),
                        widget_name: widget.name.clone(),
                    });
                }
            }
            get_map!(widget, map);
        },
        Relm(ref widget) => get_map!(widget, map),
    }
}

fn get_return_type(sig: MethodSig) -> Ty {
    if let FunctionRetTy::Ty(ty) = sig.decl.output {
        ty
    }
    else {
        panic!("Unexpected default, expecting Ty");
    }
}

fn get_second_param_type(sig: &MethodSig) -> Ty {
    if let Captured(_, ref path) = sig.decl.inputs[1] {
        path.clone()
    }
    else {
        panic!("Unexpected `{:?}`, expecting Captured Ty", sig.decl.inputs[1]);
    }
}

/*
 * TODO: Create a control flow graph for each variable of the model.
 * Add the set_property() calls in every leaf of every graphs.
 */
fn get_update(mut func: ImplItem, map: &PropertyModelMap) -> ImplItem {
    if let Method(_, ref mut block) = func.node {
        let mut adder = Adder::new(map);
        *block = adder.fold_block(block.clone());
    }
    // TODO: consider gtk::main_quit() as return.
    func
}

fn get_view(name: &Ident, state: &mut State) -> (ImplItem, PropertyModelMap, HashMap<Ident, Ident>) {
    {
        let segments = &state.view_macro.as_ref().unwrap().path.segments;
        if segments.len() != 1 || segments[0].ident != "view" {
            panic!("Unexpected macro item")
        }
    }
    impl_view(name, state)
}

fn impl_view(name: &Ident, state: &mut State) -> (ImplItem, PropertyModelMap, HashMap<Ident, Ident>) {
    let tokens = &state.view_macro.as_ref().unwrap().tts;
    if let TokenTree::Delimited(Delimited { ref tts, .. }) = tokens[0] {
        let mut widget = parse(tts);
        if let Gtk(ref mut widget) = widget {
            widget.relm_name = Some(name.clone());
            let mut components = COMPONENTS.lock().unwrap();
            components.insert(name.clone(), Component {
                msg_type: state.msg_type.clone().unwrap(),
                model_type: state.widget_model_type.clone().expect("widget model type"),
                view_type: widget.gtk_type.clone(),
            });
        }
        let mut properties_model_map = HashMap::new();
        get_properties_model_map(&widget, &mut properties_model_map);
        add_widgets(&widget, &mut state.widgets, &properties_model_map);
        let idents: Vec<_> = state.widgets.keys().collect();
        let (view, relm_widgets) = gen(name, &widget, &mut state.root_widget, &mut state.root_widget_type, &idents);
        let event_type = &state.msg_type;
        let item = block_to_impl_item(quote! {
            #[allow(unused_variables)] // Necessary to avoid warnings in case the parameters are unused.
            fn view(relm: ::relm::RemoteRelm<#event_type>, model: &Self::Model) -> Self {
                #view
            }
        });
        (item, properties_model_map, relm_widgets)
    }
    else {
        panic!("Expected `{{` but found `{:?}` in view! macro", tokens[0]);
    }
}
<commit_msg>Update to get better error messages<commit_after>/*
 * Copyright (c) 2017 Boucher, Antoni <bouanto@zoho.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

/*
 * TODO: automatically add the model() method with a () return type when it is not found?
 * FIXME: Doing model.text.push_str() will not cause a set_text() to be added.
 * TODO: think about conditions and loops (widget-list).
 */

#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate quote;
extern crate syn;

mod adder;
mod gen;
mod parser;
mod walker;

use std::collections::{HashMap, HashSet};
use std::sync::Mutex;

use adder::{Adder, Property};
use gen::gen;
use parser::Widget::{Gtk, Relm};
use parser::{Widget, parse};
use quote::{Tokens, ToTokens};
use syn::{Delimited, FunctionRetTy, Ident, ImplItem, Mac, MethodSig, TokenTree, parse_expr, parse_item};
use syn::FnArg::Captured;
use syn::fold::Folder;
use syn::ImplItemKind::{Const, Macro, Method, Type};
use syn::ItemKind::Impl;
use syn::Ty;
use syn::visit::Visitor;
use walker::ModelVariableVisitor;

type PropertyModelMap = HashMap<Ident, HashSet<Property>>;

struct Component {
    model_type: Ty,
    msg_type: Ty,
    view_type: Ident,
}

lazy_static! {
    static ref COMPONENTS: Mutex<HashMap<Ident, Component>> = Mutex::new(HashMap::new());
}

#[derive(Debug)]
struct State {
    container_method: Option<ImplItem>,
    container_type: Option<ImplItem>,
    model_type: Option<ImplItem>,
    msg_type: Option<Ty>,
    properties_model_map: Option<PropertyModelMap>,
    root_widget: Option<Ident>,
    root_widget_type: Option<Ident>,
    update_method: Option<ImplItem>,
    view_macro: Option<Mac>,
    widget_model_type: Option<Ty>,
    widgets: HashMap<Ident, Ident>, // Map widget ident to widget type.
}

impl State {
    fn new() -> Self {
        State {
            container_method: None,
            container_type: None,
            model_type: None,
            msg_type: None,
            properties_model_map: None,
            root_widget: None,
            root_widget_type: None,
            update_method: None,
            view_macro: None,
            widget_model_type: None,
            widgets: HashMap::new(),
        }
    }
}

pub fn gen_widget(input: Tokens) -> Tokens {
    let source = input.to_string();
    let mut ast = parse_item(&source).unwrap();
    if let Impl(unsafety, polarity, generics, path, typ, items) = ast.node {
        let name = get_name(&typ);
        let mut new_items = vec![];
        let mut state = State::new();
        for item in items {
            let i = item.clone();
            match item.node {
                Const(_, _) => panic!("Unexpected const item"),
                Macro(mac) => state.view_macro = Some(mac),
                Method(sig, _) => {
                    match item.ident.to_string().as_ref() {
                        "container" => state.container_method = Some(i),
                        "model" => {
                            state.widget_model_type = Some(get_return_type(sig));
                            new_items.push(i);
                        },
                        "subscriptions" | "update_command" => new_items.push(i),
                        "update" => {
                            state.msg_type = Some(get_second_param_type(&sig));
                            state.update_method = Some(i)
                        },
                        method_name => panic!("Unexpected method {}", method_name),
                    }
                },
                Type(_) => {
                    if item.ident == Ident::new("Container") {
                        state.container_type = Some(i);
                    }
                    else if item.ident == Ident::new("Model") {
                        state.model_type = Some(i);
                    }
                    else {
                        panic!("Unexpected type item {:?}", item.ident);
                    }
                },
            }
        }
        let (view, map, relm_widgets) = get_view(&name, &mut state);
        state.properties_model_map = Some(map);
        new_items.push(view);
        state.widgets.insert(state.root_widget.clone().expect("root widget"),
            state.root_widget_type.clone().expect("root widget type"));
        new_items.push(get_model_type(state.model_type, state.widget_model_type));
        new_items.push(get_container_type(state.container_type, state.root_widget_type));
        new_items.push(get_update(state.update_method.expect("update method"),
            &state.properties_model_map.expect("properties model map")));
        new_items.push(get_container(state.container_method, state.root_widget));
        let item = Impl(unsafety, polarity, generics, path, typ, new_items);
        ast.node = item;
        let widget_struct = create_struct(&name, &state.widgets, &relm_widgets);
        quote! {
            #widget_struct
            #ast
        }
    }
    else {
        panic!("Expected impl");
    }
}

fn add_widgets(widget: &Widget, widgets: &mut HashMap<Ident, Ident>, map: &PropertyModelMap) {
    // Only add widgets that are needed by the update() function.
    let mut to_add = false;
    for values in map.values() {
        for value in values {
            if value.widget_name == widget.name() {
                to_add = true;
            }
        }
    }
    if to_add {
        widgets.insert(widget.name().clone(), widget.typ().clone());
    }
    match *widget {
        Gtk(ref widget) =>  {
            for child in &widget.children {
                add_widgets(child, widgets, map);
            }
        },
        Relm(ref widget) =>  {
            for child in &widget.children {
                add_widgets(child, widgets, map);
            }
        },
    }
}

fn block_to_impl_item(tokens: Tokens) -> ImplItem {
    let implementation = quote! {
        impl Test {
            #tokens
        }
    };
    let implementation = parse_item(implementation.as_str()).unwrap();
    match implementation.node {
        Impl(_, _, _, _, _, items) => items[0].clone(),
        _ => unreachable!(),
    }
}

fn create_struct(name: &Ident, widgets: &HashMap<Ident, Ident>, relm_widgets: &HashMap<Ident, Ident>) -> Tokens {
    let widgets = widgets.iter().filter(|&(ident, _)| !relm_widgets.contains_key(ident));
    let (idents, types): (Vec<_>, Vec<_>) = widgets.unzip();
    let relm_idents = relm_widgets.keys();
    let relm_types = relm_widgets.values();
    quote! {
        #[allow(dead_code)]
        #[derive(Clone)]
        pub struct #name {
            #(#idents: #types,)*
            #(#relm_idents: #relm_types,)*
        }
    }
}

fn get_container(container_method: Option<ImplItem>, root_widget: Option<Ident>) -> ImplItem {
    container_method.unwrap_or_else(|| {
        let root_widget = root_widget.expect("root widget");
        block_to_impl_item(quote! {
            fn container(&self) -> &Self::Container {
                &self.#root_widget
            }
        })
    })
}

fn get_container_type(container_type: Option<ImplItem>, root_widget_type: Option<Ident>) -> ImplItem {
    container_type.unwrap_or_else(|| {
        let root_widget_type = root_widget_type.expect("root widget type");
        block_to_impl_item(quote! {
            type Container = #root_widget_type;
        })
    })
}

fn get_model_type(model_type: Option<ImplItem>, widget_model_type: Option<Ty>) -> ImplItem {
    model_type.unwrap_or_else(|| {
        let widget_model_type = widget_model_type.expect("missing model method");
        block_to_impl_item(quote! {
            type Model = #widget_model_type;
        })
    })
}

fn get_name(typ: &Ty) -> Ident {
    if let Ty::Path(_, ref path) = *typ {
        let mut tokens = Tokens::new();
        path.to_tokens(&mut tokens);
        Ident::new(tokens.to_string())
    }
    else {
        panic!("Expected Path")
    }
}

macro_rules! get_map {
    ($widget:expr, $map:expr) => {{
        for child in &$widget.children {
            get_properties_model_map(child, $map);
        }
    }};
}

/*
 * The map maps model variable name to a vector of tuples (widget name, property name).
 */
fn get_properties_model_map(widget: &Widget, map: &mut PropertyModelMap) {
    match *widget {
        Gtk(ref widget) => {
            for (name, value) in &widget.properties {
                let string = value.parse::<String>().unwrap();
                let expr = parse_expr(&string).unwrap();
                let mut visitor = ModelVariableVisitor::new();
                visitor.visit_expr(&expr);
                let model_variables = visitor.idents;
                for var in model_variables {
                    let set = map.entry(var).or_insert_with(HashSet::new);
                    set.insert(Property {
                        expr: string.clone(),
                        name: name.clone(),
                        widget_name: widget.name.clone(),
                    });
                }
            }
            get_map!(widget, map);
        },
        Relm(ref widget) => get_map!(widget, map),
    }
}

fn get_return_type(sig: MethodSig) -> Ty {
    if let FunctionRetTy::Ty(ty) = sig.decl.output {
        ty
    }
    else {
        panic!("Unexpected default, expecting Ty");
    }
}

fn get_second_param_type(sig: &MethodSig) -> Ty {
    if let Captured(_, ref path) = sig.decl.inputs[1] {
        path.clone()
    }
    else {
        panic!("Unexpected `{:?}`, expecting Captured Ty", sig.decl.inputs[1]);
    }
}

/*
 * TODO: Create a control flow graph for each variable of the model.
 * Add the set_property() calls in every leaf of every graphs.
 */
fn get_update(mut func: ImplItem, map: &PropertyModelMap) -> ImplItem {
    if let Method(_, ref mut block) = func.node {
        let mut adder = Adder::new(map);
        *block = adder.fold_block(block.clone());
    }
    // TODO: consider gtk::main_quit() as return.
    func
}

fn get_view(name: &Ident, state: &mut State) -> (ImplItem, PropertyModelMap, HashMap<Ident, Ident>) {
    {
        let segments = &state.view_macro.as_ref().expect("view! macro missing").path.segments;
        if segments.len() != 1 || segments[0].ident != "view" {
            panic!("Unexpected macro item")
        }
    }
    impl_view(name, state)
}

fn impl_view(name: &Ident, state: &mut State) -> (ImplItem, PropertyModelMap, HashMap<Ident, Ident>) {
    let tokens = &state.view_macro.as_ref().unwrap().tts;
    if let TokenTree::Delimited(Delimited { ref tts, .. }) = tokens[0] {
        let mut widget = parse(tts);
        if let Gtk(ref mut widget) = widget {
            widget.relm_name = Some(name.clone());
            let mut components = COMPONENTS.lock().unwrap();
            components.insert(name.clone(), Component {
                msg_type: state.msg_type.clone().expect("missing update method"),
                model_type: state.widget_model_type.clone().expect("missing model method"),
                view_type: widget.gtk_type.clone(),
            });
        }
        let mut properties_model_map = HashMap::new();
        get_properties_model_map(&widget, &mut properties_model_map);
        add_widgets(&widget, &mut state.widgets, &properties_model_map);
        let idents: Vec<_> = state.widgets.keys().collect();
        let (view, relm_widgets) = gen(name, &widget, &mut state.root_widget, &mut state.root_widget_type, &idents);
        let event_type = &state.msg_type;
        let item = block_to_impl_item(quote! {
            #[allow(unused_variables)] // Necessary to avoid warnings in case the parameters are unused.
            fn view(relm: ::relm::RemoteRelm<#event_type>, model: &Self::Model) -> Self {
                #view
            }
        });
        (item, properties_model_map, relm_widgets)
    }
    else {
        panic!("Expected `{{` but found `{:?}` in view! macro", tokens[0]);
    }
}
<|endoftext|>