<commit_before>// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]

#[macro_use]
extern crate sys_util;

// Somehow this one gets missed by bindgen
pub const KVM_EXIT_IO_OUT: ::std::os::raw::c_uint = 1;

// Each of the below modules defines ioctls specific to their platform.

#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
pub mod x86 {
    // generated with bindgen /usr/include/linux/kvm.h --no-unstable-rust --constified-enum '*' --with-derive-default
    pub mod bindings;
    pub use bindings::*;

    ioctl_iow_nr!(KVM_SET_GSI_ROUTING, KVMIO, 0x6a, kvm_irq_routing);
    ioctl_iowr_nr!(KVM_GET_MSR_INDEX_LIST, KVMIO, 0x02, kvm_msr_list);
    ioctl_iowr_nr!(KVM_GET_SUPPORTED_CPUID, KVMIO, 0x05, kvm_cpuid2);
    ioctl_iowr_nr!(KVM_GET_EMULATED_CPUID, KVMIO, 0x09, kvm_cpuid2);
    ioctl_iow_nr!(KVM_SET_MEMORY_ALIAS, KVMIO, 0x43, kvm_memory_alias);
    ioctl_iow_nr!(KVM_XEN_HVM_CONFIG, KVMIO, 0x7a, kvm_xen_hvm_config);
    ioctl_ior_nr!(KVM_GET_PIT2, KVMIO, 0x9f, kvm_pit_state2);
    ioctl_iow_nr!(KVM_SET_PIT2, KVMIO, 0xa0, kvm_pit_state2);
    ioctl_iowr_nr!(KVM_GET_MSRS, KVMIO, 0x88, kvm_msrs);
    ioctl_iow_nr!(KVM_SET_MSRS, KVMIO, 0x89, kvm_msrs);
    ioctl_iow_nr!(KVM_SET_CPUID, KVMIO, 0x8a, kvm_cpuid);
    ioctl_ior_nr!(KVM_GET_LAPIC, KVMIO, 0x8e, kvm_lapic_state);
    ioctl_iow_nr!(KVM_SET_LAPIC, KVMIO, 0x8f, kvm_lapic_state);
    ioctl_iow_nr!(KVM_SET_CPUID2, KVMIO, 0x90, kvm_cpuid2);
    ioctl_iowr_nr!(KVM_GET_CPUID2, KVMIO, 0x91, kvm_cpuid2);
    ioctl_iow_nr!(KVM_X86_SETUP_MCE, KVMIO, 0x9c, __u64);
    ioctl_ior_nr!(KVM_X86_GET_MCE_CAP_SUPPORTED, KVMIO, 0x9d, __u64);
    ioctl_iow_nr!(KVM_X86_SET_MCE, KVMIO, 0x9e, kvm_x86_mce);
    ioctl_ior_nr!(KVM_GET_VCPU_EVENTS, KVMIO, 0x9f, kvm_vcpu_events);
    ioctl_iow_nr!(KVM_SET_VCPU_EVENTS, KVMIO, 0xa0, kvm_vcpu_events);
    ioctl_ior_nr!(KVM_GET_DEBUGREGS, KVMIO, 0xa1, kvm_debugregs);
    ioctl_iow_nr!(KVM_SET_DEBUGREGS, KVMIO, 0xa2, kvm_debugregs);
    ioctl_ior_nr!(KVM_GET_XSAVE, KVMIO, 0xa4, kvm_xsave);
    ioctl_iow_nr!(KVM_SET_XSAVE, KVMIO, 0xa5, kvm_xsave);
    ioctl_ior_nr!(KVM_GET_XCRS, KVMIO, 0xa6, kvm_xcrs);
    ioctl_iowr_nr!(KVM_SET_XCRS, KVMIO, 0xa7, kvm_xcrs);
}

#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
pub mod aarch64 {
    // generated with bindgen <arm sysroot>/usr/include/linux/kvm.h --no-unstable-rust --constified-enum '*' --with-derive-default -- -I<arm sysroot>/usr/include
    pub mod bindings;
    pub use bindings::*;

    ioctl_iow_nr!(KVM_ARM_SET_DEVICE_ADDR, KVMIO, 0xab, kvm_arm_device_addr);
    ioctl_iow_nr!(KVM_ARM_VCPU_INIT, KVMIO, 0xae, kvm_vcpu_init);
    ioctl_ior_nr!(KVM_ARM_PREFERRED_TARGET, KVMIO, 0xaf, kvm_vcpu_init);
}

// These ioctls are commonly defined on all/multiple platforms.
ioctl_io_nr!(KVM_GET_API_VERSION, KVMIO, 0x00);
ioctl_io_nr!(KVM_CREATE_VM, KVMIO, 0x01);
ioctl_io_nr!(KVM_CHECK_EXTENSION, KVMIO, 0x03);
ioctl_io_nr!(KVM_GET_VCPU_MMAP_SIZE, KVMIO, 0x04) /* in bytes */;
ioctl_iow_nr!(KVM_SET_MEMORY_REGION, KVMIO, 0x40, kvm_memory_region);
ioctl_io_nr!(KVM_CREATE_VCPU, KVMIO, 0x41);
ioctl_iow_nr!(KVM_GET_DIRTY_LOG, KVMIO, 0x42, kvm_dirty_log);
ioctl_io_nr!(KVM_SET_NR_MMU_PAGES, KVMIO, 0x44);
ioctl_io_nr!(KVM_GET_NR_MMU_PAGES, KVMIO, 0x45);
ioctl_iow_nr!(KVM_SET_USER_MEMORY_REGION,KVMIO, 0x46, kvm_userspace_memory_region);
ioctl_io_nr!(KVM_SET_TSS_ADDR, KVMIO, 0x47);
ioctl_iow_nr!(KVM_SET_IDENTITY_MAP_ADDR, KVMIO, 0x48, __u64);
ioctl_io_nr!(KVM_CREATE_IRQCHIP, KVMIO, 0x60);
ioctl_iow_nr!(KVM_IRQ_LINE, KVMIO, 0x61, kvm_irq_level);
ioctl_iowr_nr!(KVM_GET_IRQCHIP, KVMIO, 0x62, kvm_irqchip);
ioctl_ior_nr!(KVM_SET_IRQCHIP, KVMIO, 0x63, kvm_irqchip);
ioctl_io_nr!(KVM_CREATE_PIT, KVMIO, 0x64);
ioctl_iowr_nr!(KVM_IRQ_LINE_STATUS, KVMIO, 0x67, kvm_irq_level);
ioctl_iow_nr!(KVM_REGISTER_COALESCED_MMIO, KVMIO, 0x67, kvm_coalesced_mmio_zone);
ioctl_iow_nr!(KVM_UNREGISTER_COALESCED_MMIO, KVMIO, 0x68, kvm_coalesced_mmio_zone);
ioctl_ior_nr!(KVM_ASSIGN_PCI_DEVICE, KVMIO, 0x69,  kvm_assigned_pci_dev);
ioctl_iow_nr!(KVM_ASSIGN_DEV_IRQ, KVMIO, 0x70, kvm_assigned_irq);
ioctl_io_nr!(KVM_REINJECT_CONTROL, KVMIO, 0x71);
ioctl_iow_nr!(KVM_DEASSIGN_PCI_DEVICE, KVMIO, 0x72,  kvm_assigned_pci_dev);
ioctl_iow_nr!(KVM_ASSIGN_SET_MSIX_NR, KVMIO, 0x73,  kvm_assigned_msix_nr);
ioctl_iow_nr!(KVM_ASSIGN_SET_MSIX_ENTRY, KVMIO, 0x74,  kvm_assigned_msix_entry);
ioctl_iow_nr!(KVM_DEASSIGN_DEV_IRQ, KVMIO, 0x75, kvm_assigned_irq);
ioctl_iow_nr!(KVM_IRQFD, KVMIO, 0x76, kvm_irqfd);
ioctl_iow_nr!(KVM_CREATE_PIT2, KVMIO, 0x77, kvm_pit_config);
ioctl_io_nr!(KVM_SET_BOOT_CPU_ID, KVMIO, 0x78);
ioctl_iow_nr!(KVM_IOEVENTFD, KVMIO, 0x79, kvm_ioeventfd);
ioctl_iow_nr!(KVM_SET_CLOCK, KVMIO, 0x7b, kvm_clock_data);
ioctl_ior_nr!(KVM_GET_CLOCK, KVMIO, 0x7c, kvm_clock_data);
ioctl_io_nr!(KVM_SET_TSC_KHZ, KVMIO, 0xa2);
ioctl_io_nr!(KVM_GET_TSC_KHZ, KVMIO, 0xa3);
ioctl_iow_nr!(KVM_ASSIGN_SET_INTX_MASK, KVMIO, 0xa4,  kvm_assigned_pci_dev);
ioctl_iow_nr!(KVM_SIGNAL_MSI, KVMIO, 0xa5, kvm_msi);
ioctl_iowr_nr!(KVM_CREATE_DEVICE, KVMIO, 0xe0, kvm_create_device);
ioctl_iow_nr!(KVM_SET_DEVICE_ATTR, KVMIO, 0xe1, kvm_device_attr);
ioctl_iow_nr!(KVM_GET_DEVICE_ATTR, KVMIO, 0xe2, kvm_device_attr);
ioctl_iow_nr!(KVM_HAS_DEVICE_ATTR, KVMIO, 0xe3, kvm_device_attr);
ioctl_io_nr!(KVM_RUN, KVMIO, 0x80);
// The following two ioctls are commonly defined but specifically excluded
// from arm platforms.
#[cfg(not(any(target_arch = "arm", target_arch = "aarch64")))]
ioctl_ior_nr!(KVM_GET_REGS, KVMIO, 0x81, kvm_regs);
#[cfg(not(any(target_arch = "arm", target_arch = "aarch64")))]
ioctl_iow_nr!(KVM_SET_REGS, KVMIO, 0x82, kvm_regs);
ioctl_ior_nr!(KVM_GET_SREGS, KVMIO, 0x83, kvm_sregs);
ioctl_iow_nr!(KVM_SET_SREGS, KVMIO, 0x84, kvm_sregs);
ioctl_iowr_nr!(KVM_TRANSLATE, KVMIO, 0x85, kvm_translation);
ioctl_iow_nr!(KVM_INTERRUPT, KVMIO, 0x86, kvm_interrupt);
ioctl_iow_nr!(KVM_SET_SIGNAL_MASK, KVMIO, 0x8b, kvm_signal_mask);
ioctl_ior_nr!(KVM_GET_FPU, KVMIO, 0x8c, kvm_fpu);
ioctl_iow_nr!(KVM_SET_FPU, KVMIO, 0x8d, kvm_fpu);
ioctl_iowr_nr!(KVM_TPR_ACCESS_REPORTING, KVMIO, 0x92, kvm_tpr_access_ctl);
ioctl_iow_nr!(KVM_SET_VAPIC_ADDR, KVMIO, 0x93, kvm_vapic_addr);
ioctl_ior_nr!(KVM_GET_MP_STATE, KVMIO, 0x98, kvm_mp_state);
ioctl_iow_nr!(KVM_SET_MP_STATE, KVMIO, 0x99, kvm_mp_state);
ioctl_io_nr!(KVM_NMI, KVMIO, 0x9a);
ioctl_iow_nr!(KVM_SET_GUEST_DEBUG, KVMIO, 0x9b, kvm_guest_debug);
ioctl_iow_nr!(KVM_ENABLE_CAP, KVMIO, 0xa3, kvm_enable_cap);
ioctl_iow_nr!(KVM_DIRTY_TLB, KVMIO, 0xaa, kvm_dirty_tlb);
ioctl_iow_nr!(KVM_GET_ONE_REG, KVMIO, 0xab, kvm_one_reg);
ioctl_iow_nr!(KVM_SET_ONE_REG, KVMIO, 0xac, kvm_one_reg);
ioctl_io_nr!(KVM_KVMCLOCK_CTRL, KVMIO, 0xad);
ioctl_iowr_nr!(KVM_GET_REG_LIST, KVMIO, 0xb0, kvm_reg_list);
ioctl_io_nr!(KVM_SMI, KVMIO, 0xb7);

// Along with the common ioctls, we reexport the ioctls of the current
// platform.

#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
pub use x86::*;

#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
pub use aarch64::*;
<commit_msg>kvm: fix definition of KVM_SET_XCRS ioctl<commit_after>// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]

#[macro_use]
extern crate sys_util;

// Somehow this one gets missed by bindgen
pub const KVM_EXIT_IO_OUT: ::std::os::raw::c_uint = 1;

// Each of the below modules defines ioctls specific to their platform.

#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
pub mod x86 {
    // generated with bindgen /usr/include/linux/kvm.h --no-unstable-rust --constified-enum '*' --with-derive-default
    pub mod bindings;
    pub use bindings::*;

    ioctl_iow_nr!(KVM_SET_GSI_ROUTING, KVMIO, 0x6a, kvm_irq_routing);
    ioctl_iowr_nr!(KVM_GET_MSR_INDEX_LIST, KVMIO, 0x02, kvm_msr_list);
    ioctl_iowr_nr!(KVM_GET_SUPPORTED_CPUID, KVMIO, 0x05, kvm_cpuid2);
    ioctl_iowr_nr!(KVM_GET_EMULATED_CPUID, KVMIO, 0x09, kvm_cpuid2);
    ioctl_iow_nr!(KVM_SET_MEMORY_ALIAS, KVMIO, 0x43, kvm_memory_alias);
    ioctl_iow_nr!(KVM_XEN_HVM_CONFIG, KVMIO, 0x7a, kvm_xen_hvm_config);
    ioctl_ior_nr!(KVM_GET_PIT2, KVMIO, 0x9f, kvm_pit_state2);
    ioctl_iow_nr!(KVM_SET_PIT2, KVMIO, 0xa0, kvm_pit_state2);
    ioctl_iowr_nr!(KVM_GET_MSRS, KVMIO, 0x88, kvm_msrs);
    ioctl_iow_nr!(KVM_SET_MSRS, KVMIO, 0x89, kvm_msrs);
    ioctl_iow_nr!(KVM_SET_CPUID, KVMIO, 0x8a, kvm_cpuid);
    ioctl_ior_nr!(KVM_GET_LAPIC, KVMIO, 0x8e, kvm_lapic_state);
    ioctl_iow_nr!(KVM_SET_LAPIC, KVMIO, 0x8f, kvm_lapic_state);
    ioctl_iow_nr!(KVM_SET_CPUID2, KVMIO, 0x90, kvm_cpuid2);
    ioctl_iowr_nr!(KVM_GET_CPUID2, KVMIO, 0x91, kvm_cpuid2);
    ioctl_iow_nr!(KVM_X86_SETUP_MCE, KVMIO, 0x9c, __u64);
    ioctl_ior_nr!(KVM_X86_GET_MCE_CAP_SUPPORTED, KVMIO, 0x9d, __u64);
    ioctl_iow_nr!(KVM_X86_SET_MCE, KVMIO, 0x9e, kvm_x86_mce);
    ioctl_ior_nr!(KVM_GET_VCPU_EVENTS, KVMIO, 0x9f, kvm_vcpu_events);
    ioctl_iow_nr!(KVM_SET_VCPU_EVENTS, KVMIO, 0xa0, kvm_vcpu_events);
    ioctl_ior_nr!(KVM_GET_DEBUGREGS, KVMIO, 0xa1, kvm_debugregs);
    ioctl_iow_nr!(KVM_SET_DEBUGREGS, KVMIO, 0xa2, kvm_debugregs);
    ioctl_ior_nr!(KVM_GET_XSAVE, KVMIO, 0xa4, kvm_xsave);
    ioctl_iow_nr!(KVM_SET_XSAVE, KVMIO, 0xa5, kvm_xsave);
    ioctl_ior_nr!(KVM_GET_XCRS, KVMIO, 0xa6, kvm_xcrs);
    ioctl_iow_nr!(KVM_SET_XCRS, KVMIO, 0xa7, kvm_xcrs);
}

#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
pub mod aarch64 {
    // generated with bindgen <arm sysroot>/usr/include/linux/kvm.h --no-unstable-rust --constified-enum '*' --with-derive-default -- -I<arm sysroot>/usr/include
    pub mod bindings;
    pub use bindings::*;

    ioctl_iow_nr!(KVM_ARM_SET_DEVICE_ADDR, KVMIO, 0xab, kvm_arm_device_addr);
    ioctl_iow_nr!(KVM_ARM_VCPU_INIT, KVMIO, 0xae, kvm_vcpu_init);
    ioctl_ior_nr!(KVM_ARM_PREFERRED_TARGET, KVMIO, 0xaf, kvm_vcpu_init);
}

// These ioctls are commonly defined on all/multiple platforms.
ioctl_io_nr!(KVM_GET_API_VERSION, KVMIO, 0x00);
ioctl_io_nr!(KVM_CREATE_VM, KVMIO, 0x01);
ioctl_io_nr!(KVM_CHECK_EXTENSION, KVMIO, 0x03);
ioctl_io_nr!(KVM_GET_VCPU_MMAP_SIZE, KVMIO, 0x04) /* in bytes */;
ioctl_iow_nr!(KVM_SET_MEMORY_REGION, KVMIO, 0x40, kvm_memory_region);
ioctl_io_nr!(KVM_CREATE_VCPU, KVMIO, 0x41);
ioctl_iow_nr!(KVM_GET_DIRTY_LOG, KVMIO, 0x42, kvm_dirty_log);
ioctl_io_nr!(KVM_SET_NR_MMU_PAGES, KVMIO, 0x44);
ioctl_io_nr!(KVM_GET_NR_MMU_PAGES, KVMIO, 0x45);
ioctl_iow_nr!(KVM_SET_USER_MEMORY_REGION,KVMIO, 0x46, kvm_userspace_memory_region);
ioctl_io_nr!(KVM_SET_TSS_ADDR, KVMIO, 0x47);
ioctl_iow_nr!(KVM_SET_IDENTITY_MAP_ADDR, KVMIO, 0x48, __u64);
ioctl_io_nr!(KVM_CREATE_IRQCHIP, KVMIO, 0x60);
ioctl_iow_nr!(KVM_IRQ_LINE, KVMIO, 0x61, kvm_irq_level);
ioctl_iowr_nr!(KVM_GET_IRQCHIP, KVMIO, 0x62, kvm_irqchip);
ioctl_ior_nr!(KVM_SET_IRQCHIP, KVMIO, 0x63, kvm_irqchip);
ioctl_io_nr!(KVM_CREATE_PIT, KVMIO, 0x64);
ioctl_iowr_nr!(KVM_IRQ_LINE_STATUS, KVMIO, 0x67, kvm_irq_level);
ioctl_iow_nr!(KVM_REGISTER_COALESCED_MMIO, KVMIO, 0x67, kvm_coalesced_mmio_zone);
ioctl_iow_nr!(KVM_UNREGISTER_COALESCED_MMIO, KVMIO, 0x68, kvm_coalesced_mmio_zone);
ioctl_ior_nr!(KVM_ASSIGN_PCI_DEVICE, KVMIO, 0x69,  kvm_assigned_pci_dev);
ioctl_iow_nr!(KVM_ASSIGN_DEV_IRQ, KVMIO, 0x70, kvm_assigned_irq);
ioctl_io_nr!(KVM_REINJECT_CONTROL, KVMIO, 0x71);
ioctl_iow_nr!(KVM_DEASSIGN_PCI_DEVICE, KVMIO, 0x72,  kvm_assigned_pci_dev);
ioctl_iow_nr!(KVM_ASSIGN_SET_MSIX_NR, KVMIO, 0x73,  kvm_assigned_msix_nr);
ioctl_iow_nr!(KVM_ASSIGN_SET_MSIX_ENTRY, KVMIO, 0x74,  kvm_assigned_msix_entry);
ioctl_iow_nr!(KVM_DEASSIGN_DEV_IRQ, KVMIO, 0x75, kvm_assigned_irq);
ioctl_iow_nr!(KVM_IRQFD, KVMIO, 0x76, kvm_irqfd);
ioctl_iow_nr!(KVM_CREATE_PIT2, KVMIO, 0x77, kvm_pit_config);
ioctl_io_nr!(KVM_SET_BOOT_CPU_ID, KVMIO, 0x78);
ioctl_iow_nr!(KVM_IOEVENTFD, KVMIO, 0x79, kvm_ioeventfd);
ioctl_iow_nr!(KVM_SET_CLOCK, KVMIO, 0x7b, kvm_clock_data);
ioctl_ior_nr!(KVM_GET_CLOCK, KVMIO, 0x7c, kvm_clock_data);
ioctl_io_nr!(KVM_SET_TSC_KHZ, KVMIO, 0xa2);
ioctl_io_nr!(KVM_GET_TSC_KHZ, KVMIO, 0xa3);
ioctl_iow_nr!(KVM_ASSIGN_SET_INTX_MASK, KVMIO, 0xa4,  kvm_assigned_pci_dev);
ioctl_iow_nr!(KVM_SIGNAL_MSI, KVMIO, 0xa5, kvm_msi);
ioctl_iowr_nr!(KVM_CREATE_DEVICE, KVMIO, 0xe0, kvm_create_device);
ioctl_iow_nr!(KVM_SET_DEVICE_ATTR, KVMIO, 0xe1, kvm_device_attr);
ioctl_iow_nr!(KVM_GET_DEVICE_ATTR, KVMIO, 0xe2, kvm_device_attr);
ioctl_iow_nr!(KVM_HAS_DEVICE_ATTR, KVMIO, 0xe3, kvm_device_attr);
ioctl_io_nr!(KVM_RUN, KVMIO, 0x80);
// The following two ioctls are commonly defined but specifically excluded
// from arm platforms.
#[cfg(not(any(target_arch = "arm", target_arch = "aarch64")))]
ioctl_ior_nr!(KVM_GET_REGS, KVMIO, 0x81, kvm_regs);
#[cfg(not(any(target_arch = "arm", target_arch = "aarch64")))]
ioctl_iow_nr!(KVM_SET_REGS, KVMIO, 0x82, kvm_regs);
ioctl_ior_nr!(KVM_GET_SREGS, KVMIO, 0x83, kvm_sregs);
ioctl_iow_nr!(KVM_SET_SREGS, KVMIO, 0x84, kvm_sregs);
ioctl_iowr_nr!(KVM_TRANSLATE, KVMIO, 0x85, kvm_translation);
ioctl_iow_nr!(KVM_INTERRUPT, KVMIO, 0x86, kvm_interrupt);
ioctl_iow_nr!(KVM_SET_SIGNAL_MASK, KVMIO, 0x8b, kvm_signal_mask);
ioctl_ior_nr!(KVM_GET_FPU, KVMIO, 0x8c, kvm_fpu);
ioctl_iow_nr!(KVM_SET_FPU, KVMIO, 0x8d, kvm_fpu);
ioctl_iowr_nr!(KVM_TPR_ACCESS_REPORTING, KVMIO, 0x92, kvm_tpr_access_ctl);
ioctl_iow_nr!(KVM_SET_VAPIC_ADDR, KVMIO, 0x93, kvm_vapic_addr);
ioctl_ior_nr!(KVM_GET_MP_STATE, KVMIO, 0x98, kvm_mp_state);
ioctl_iow_nr!(KVM_SET_MP_STATE, KVMIO, 0x99, kvm_mp_state);
ioctl_io_nr!(KVM_NMI, KVMIO, 0x9a);
ioctl_iow_nr!(KVM_SET_GUEST_DEBUG, KVMIO, 0x9b, kvm_guest_debug);
ioctl_iow_nr!(KVM_ENABLE_CAP, KVMIO, 0xa3, kvm_enable_cap);
ioctl_iow_nr!(KVM_DIRTY_TLB, KVMIO, 0xaa, kvm_dirty_tlb);
ioctl_iow_nr!(KVM_GET_ONE_REG, KVMIO, 0xab, kvm_one_reg);
ioctl_iow_nr!(KVM_SET_ONE_REG, KVMIO, 0xac, kvm_one_reg);
ioctl_io_nr!(KVM_KVMCLOCK_CTRL, KVMIO, 0xad);
ioctl_iowr_nr!(KVM_GET_REG_LIST, KVMIO, 0xb0, kvm_reg_list);
ioctl_io_nr!(KVM_SMI, KVMIO, 0xb7);

// Along with the common ioctls, we reexport the ioctls of the current
// platform.

#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
pub use x86::*;

#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
pub use aarch64::*;
<|endoftext|>


<commit_before>//! Implementation of the install aspects of the compiler.
//!
//! This module is responsible for installing the standard library,
//! compiler, and documentation.

use std::env;
use std::fs;
use std::path::{Component, Path, PathBuf};
use std::process::Command;

use build_helper::t;

use crate::dist::{self, pkgname, sanitize_sh, tmpdir};
use crate::Compiler;

use crate::builder::{Builder, RunConfig, ShouldRun, Step};
use crate::cache::Interned;
use crate::config::Config;

pub fn install_docs(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
    install_sh(builder, "docs", "rust-docs", stage, Some(host));
}

pub fn install_std(builder: &Builder<'_>, stage: u32, target: Interned<String>) {
    install_sh(builder, "std", "rust-std", stage, Some(target));
}

pub fn install_cargo(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
    install_sh(builder, "cargo", "cargo", stage, Some(host));
}

pub fn install_rls(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
    install_sh(builder, "rls", "rls", stage, Some(host));
}
pub fn install_clippy(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
    install_sh(builder, "clippy", "clippy", stage, Some(host));
}
pub fn install_miri(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
    install_sh(builder, "miri", "miri", stage, Some(host));
}

pub fn install_rustfmt(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
    install_sh(builder, "rustfmt", "rustfmt", stage, Some(host));
}

pub fn install_analysis(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
    install_sh(builder, "analysis", "rust-analysis", stage, Some(host));
}

pub fn install_src(builder: &Builder<'_>, stage: u32) {
    install_sh(builder, "src", "rust-src", stage, None);
}
pub fn install_rustc(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
    install_sh(builder, "rustc", "rustc", stage, Some(host));
}

fn install_sh(
    builder: &Builder<'_>,
    package: &str,
    name: &str,
    stage: u32,
    host: Option<Interned<String>>,
) {
    builder.info(&format!("Install {} stage{} ({:?})", package, stage, host));

    let prefix_default = PathBuf::from("/usr/local");
    let sysconfdir_default = PathBuf::from("/etc");
    let datadir_default = PathBuf::from("share");
    let docdir_default = datadir_default.join("doc/rust");
    let bindir_default = PathBuf::from("bin");
    let libdir_default = PathBuf::from("lib");
    let mandir_default = datadir_default.join("man");
    let prefix = builder.config.prefix.as_ref().map_or(prefix_default, |p| {
        fs::canonicalize(p).unwrap_or_else(|_| panic!("could not canonicalize {}", p.display()))
    });
    let sysconfdir = builder.config.sysconfdir.as_ref().unwrap_or(&sysconfdir_default);
    let datadir = builder.config.datadir.as_ref().unwrap_or(&datadir_default);
    let docdir = builder.config.docdir.as_ref().unwrap_or(&docdir_default);
    let bindir = builder.config.bindir.as_ref().unwrap_or(&bindir_default);
    let libdir = builder.config.libdir.as_ref().unwrap_or(&libdir_default);
    let mandir = builder.config.mandir.as_ref().unwrap_or(&mandir_default);

    let sysconfdir = prefix.join(sysconfdir);
    let datadir = prefix.join(datadir);
    let docdir = prefix.join(docdir);
    let bindir = prefix.join(bindir);
    let libdir = prefix.join(libdir);
    let mandir = prefix.join(mandir);

    let destdir = env::var_os("DESTDIR").map(PathBuf::from);

    let prefix = add_destdir(&prefix, &destdir);
    let sysconfdir = add_destdir(&sysconfdir, &destdir);
    let datadir = add_destdir(&datadir, &destdir);
    let docdir = add_destdir(&docdir, &destdir);
    let bindir = add_destdir(&bindir, &destdir);
    let libdir = add_destdir(&libdir, &destdir);
    let mandir = add_destdir(&mandir, &destdir);

    let empty_dir = builder.out.join("tmp/empty_dir");

    t!(fs::create_dir_all(&empty_dir));
    let package_name = if let Some(host) = host {
        format!("{}-{}", pkgname(builder, name), host)
    } else {
        pkgname(builder, name)
    };

    let mut cmd = Command::new("sh");
    cmd.current_dir(&empty_dir)
        .arg(sanitize_sh(&tmpdir(builder).join(&package_name).join("install.sh")))
        .arg(format!("--prefix={}", sanitize_sh(&prefix)))
        .arg(format!("--sysconfdir={}", sanitize_sh(&sysconfdir)))
        .arg(format!("--datadir={}", sanitize_sh(&datadir)))
        .arg(format!("--docdir={}", sanitize_sh(&docdir)))
        .arg(format!("--bindir={}", sanitize_sh(&bindir)))
        .arg(format!("--libdir={}", sanitize_sh(&libdir)))
        .arg(format!("--mandir={}", sanitize_sh(&mandir)))
        .arg("--disable-ldconfig");
    builder.run(&mut cmd);
    t!(fs::remove_dir_all(&empty_dir));
}

fn add_destdir(path: &Path, destdir: &Option<PathBuf>) -> PathBuf {
    let mut ret = match *destdir {
        Some(ref dest) => dest.clone(),
        None => return path.to_path_buf(),
    };
    for part in path.components() {
        match part {
            Component::Normal(s) => ret.push(s),
            _ => {}
        }
    }
    ret
}

macro_rules! install {
    (($sel:ident, $builder:ident, $_config:ident),
       $($name:ident,
       $path:expr,
       $default_cond:expr,
       only_hosts: $only_hosts:expr,
       $run_item:block $(, $c:ident)*;)+) => {
        $(
            #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
        pub struct $name {
            pub compiler: Compiler,
            pub target: Interned<String>,
        }

        impl $name {
            #[allow(dead_code)]
            fn should_build(config: &Config) -> bool {
                config.extended && config.tools.as_ref()
                    .map_or(true, |t| t.contains($path))
            }

            #[allow(dead_code)]
            fn should_install(builder: &Builder<'_>) -> bool {
                builder.config.tools.as_ref().map_or(false, |t| t.contains($path))
            }
        }

        impl Step for $name {
            type Output = ();
            const DEFAULT: bool = true;
            const ONLY_HOSTS: bool = $only_hosts;
            $(const $c: bool = true;)*

            fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
                let $_config = &run.builder.config;
                run.path($path).default_condition($default_cond)
            }

            fn make_run(run: RunConfig<'_>) {
                run.builder.ensure($name {
                    compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
                    target: run.target,
                });
            }

            fn run($sel, $builder: &Builder<'_>) {
                $run_item
            }
        })+
    }
}

install!((self, builder, _config),
    Docs, "src/doc", _config.docs, only_hosts: false, {
        builder.ensure(dist::Docs { host: self.target });
        install_docs(builder, self.compiler.stage, self.target);
    };
    Std, "src/libstd", true, only_hosts: true, {
        for target in &builder.targets {
            builder.ensure(dist::Std {
                compiler: self.compiler,
                target: *target
            });
            install_std(builder, self.compiler.stage, *target);
        }
    };
    Cargo, "cargo", Self::should_build(_config), only_hosts: true, {
        builder.ensure(dist::Cargo { compiler: self.compiler, target: self.target });
        install_cargo(builder, self.compiler.stage, self.target);
    };
    Rls, "rls", Self::should_build(_config), only_hosts: true, {
        if builder.ensure(dist::Rls { compiler: self.compiler, target: self.target }).is_some() ||
            Self::should_install(builder) {
            install_rls(builder, self.compiler.stage, self.target);
        } else {
            builder.info(
                &format!("skipping Install RLS stage{} ({})", self.compiler.stage, self.target),
            );
        }
    };
    Clippy, "clippy", Self::should_build(_config), only_hosts: true, {
        if builder.ensure(dist::Clippy {
            compiler: self.compiler,
            target: self.target,
        }).is_some() || Self::should_install(builder) {
            install_clippy(builder, self.compiler.stage, self.target);
        } else {
            builder.info(
                &format!("skipping Install clippy stage{} ({})", self.compiler.stage, self.target),
            );
        }
    };
    Miri, "miri", Self::should_build(_config), only_hosts: true, {
        if builder.ensure(dist::Miri { compiler: self.compiler, target: self.target }).is_some() ||
            Self::should_install(builder) {
            install_miri(builder, self.compiler.stage, self.target);
        } else {
            builder.info(
                &format!("skipping Install miri stage{} ({})", self.compiler.stage, self.target),
            );
        }
    };
    Rustfmt, "rustfmt", Self::should_build(_config), only_hosts: true, {
        if builder.ensure(dist::Rustfmt {
            compiler: self.compiler,
            target: self.target
        }).is_some() || Self::should_install(builder) {
            install_rustfmt(builder, self.compiler.stage, self.target);
        } else {
            builder.info(
                &format!("skipping Install Rustfmt stage{} ({})", self.compiler.stage, self.target),
            );
        }
    };
    Analysis, "analysis", Self::should_build(_config), only_hosts: false, {
        builder.ensure(dist::Analysis {
            compiler: self.compiler,
            target: self.target
        });
        install_analysis(builder, self.compiler.stage, self.target);
    };
    Rustc, "src/librustc", true, only_hosts: true, {
        builder.ensure(dist::Rustc {
            compiler: self.compiler,
        });
        install_rustc(builder, self.compiler.stage, self.target);
    };
);

#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct Src {
    pub stage: u32,
}

impl Step for Src {
    type Output = ();
    const DEFAULT: bool = true;
    const ONLY_HOSTS: bool = true;

    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
        let config = &run.builder.config;
        let cond = config.extended && config.tools.as_ref().map_or(true, |t| t.contains("src"));
        run.path("src").default_condition(cond)
    }

    fn make_run(run: RunConfig<'_>) {
        run.builder.ensure(Src { stage: run.builder.top_stage });
    }

    fn run(self, builder: &Builder<'_>) {
        builder.ensure(dist::Src);
        install_src(builder, self.stage);
    }
}
<commit_msg>Rollup merge of #61750 - tmandry:fix-install, r=Mark-Simulacrum<commit_after>//! Implementation of the install aspects of the compiler.
//!
//! This module is responsible for installing the standard library,
//! compiler, and documentation.

use std::env;
use std::fs;
use std::path::{Component, Path, PathBuf};
use std::process::Command;

use build_helper::t;

use crate::dist::{self, pkgname, sanitize_sh, tmpdir};
use crate::Compiler;

use crate::builder::{Builder, RunConfig, ShouldRun, Step};
use crate::cache::Interned;
use crate::config::Config;

pub fn install_docs(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
    install_sh(builder, "docs", "rust-docs", stage, Some(host));
}

pub fn install_std(builder: &Builder<'_>, stage: u32, target: Interned<String>) {
    install_sh(builder, "std", "rust-std", stage, Some(target));
}

pub fn install_cargo(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
    install_sh(builder, "cargo", "cargo", stage, Some(host));
}

pub fn install_rls(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
    install_sh(builder, "rls", "rls", stage, Some(host));
}
pub fn install_clippy(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
    install_sh(builder, "clippy", "clippy", stage, Some(host));
}
pub fn install_miri(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
    install_sh(builder, "miri", "miri", stage, Some(host));
}

pub fn install_rustfmt(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
    install_sh(builder, "rustfmt", "rustfmt", stage, Some(host));
}

pub fn install_analysis(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
    install_sh(builder, "analysis", "rust-analysis", stage, Some(host));
}

pub fn install_src(builder: &Builder<'_>, stage: u32) {
    install_sh(builder, "src", "rust-src", stage, None);
}
pub fn install_rustc(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
    install_sh(builder, "rustc", "rustc", stage, Some(host));
}

fn install_sh(
    builder: &Builder<'_>,
    package: &str,
    name: &str,
    stage: u32,
    host: Option<Interned<String>>,
) {
    builder.info(&format!("Install {} stage{} ({:?})", package, stage, host));

    let prefix_default = PathBuf::from("/usr/local");
    let sysconfdir_default = PathBuf::from("/etc");
    let datadir_default = PathBuf::from("share");
    let docdir_default = datadir_default.join("doc/rust");
    let bindir_default = PathBuf::from("bin");
    let libdir_default = PathBuf::from("lib");
    let mandir_default = datadir_default.join("man");
    let prefix = builder.config.prefix.as_ref().map_or(prefix_default, |p| {
        fs::canonicalize(p).unwrap_or_else(|_| panic!("could not canonicalize {}", p.display()))
    });
    let sysconfdir = builder.config.sysconfdir.as_ref().unwrap_or(&sysconfdir_default);
    let datadir = builder.config.datadir.as_ref().unwrap_or(&datadir_default);
    let docdir = builder.config.docdir.as_ref().unwrap_or(&docdir_default);
    let bindir = builder.config.bindir.as_ref().unwrap_or(&bindir_default);
    let libdir = builder.config.libdir.as_ref().unwrap_or(&libdir_default);
    let mandir = builder.config.mandir.as_ref().unwrap_or(&mandir_default);

    let sysconfdir = prefix.join(sysconfdir);
    let datadir = prefix.join(datadir);
    let docdir = prefix.join(docdir);
    let bindir = prefix.join(bindir);
    let libdir = prefix.join(libdir);
    let mandir = prefix.join(mandir);

    let destdir = env::var_os("DESTDIR").map(PathBuf::from);

    let prefix = add_destdir(&prefix, &destdir);
    let sysconfdir = add_destdir(&sysconfdir, &destdir);
    let datadir = add_destdir(&datadir, &destdir);
    let docdir = add_destdir(&docdir, &destdir);
    let bindir = add_destdir(&bindir, &destdir);
    let libdir = add_destdir(&libdir, &destdir);
    let mandir = add_destdir(&mandir, &destdir);

    let empty_dir = builder.out.join("tmp/empty_dir");

    t!(fs::create_dir_all(&empty_dir));
    let package_name = if let Some(host) = host {
        format!("{}-{}", pkgname(builder, name), host)
    } else {
        pkgname(builder, name)
    };

    let mut cmd = Command::new("sh");
    cmd.current_dir(&empty_dir)
        .arg(sanitize_sh(&tmpdir(builder).join(&package_name).join("install.sh")))
        .arg(format!("--prefix={}", sanitize_sh(&prefix)))
        .arg(format!("--sysconfdir={}", sanitize_sh(&sysconfdir)))
        .arg(format!("--datadir={}", sanitize_sh(&datadir)))
        .arg(format!("--docdir={}", sanitize_sh(&docdir)))
        .arg(format!("--bindir={}", sanitize_sh(&bindir)))
        .arg(format!("--libdir={}", sanitize_sh(&libdir)))
        .arg(format!("--mandir={}", sanitize_sh(&mandir)))
        .arg("--disable-ldconfig");
    builder.run(&mut cmd);
    t!(fs::remove_dir_all(&empty_dir));
}

fn add_destdir(path: &Path, destdir: &Option<PathBuf>) -> PathBuf {
    let mut ret = match *destdir {
        Some(ref dest) => dest.clone(),
        None => return path.to_path_buf(),
    };
    for part in path.components() {
        match part {
            Component::Normal(s) => ret.push(s),
            _ => {}
        }
    }
    ret
}

macro_rules! install {
    (($sel:ident, $builder:ident, $_config:ident),
       $($name:ident,
       $path:expr,
       $default_cond:expr,
       only_hosts: $only_hosts:expr,
       $run_item:block $(, $c:ident)*;)+) => {
        $(
            #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
        pub struct $name {
            pub compiler: Compiler,
            pub target: Interned<String>,
        }

        impl $name {
            #[allow(dead_code)]
            fn should_build(config: &Config) -> bool {
                config.extended && config.tools.as_ref()
                    .map_or(true, |t| t.contains($path))
            }

            #[allow(dead_code)]
            fn should_install(builder: &Builder<'_>) -> bool {
                builder.config.tools.as_ref().map_or(false, |t| t.contains($path))
            }
        }

        impl Step for $name {
            type Output = ();
            const DEFAULT: bool = true;
            const ONLY_HOSTS: bool = $only_hosts;
            $(const $c: bool = true;)*

            fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
                let $_config = &run.builder.config;
                run.path($path).default_condition($default_cond)
            }

            fn make_run(run: RunConfig<'_>) {
                run.builder.ensure($name {
                    compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
                    target: run.target,
                });
            }

            fn run($sel, $builder: &Builder<'_>) {
                $run_item
            }
        })+
    }
}

install!((self, builder, _config),
    Docs, "src/doc", _config.docs, only_hosts: false, {
        builder.ensure(dist::Docs { host: self.target });
        install_docs(builder, self.compiler.stage, self.target);
    };
    Std, "src/libstd", true, only_hosts: true, {
        for target in &builder.targets {
            builder.ensure(dist::Std {
                compiler: self.compiler,
                target: *target
            });
            install_std(builder, self.compiler.stage, *target);
        }
    };
    Cargo, "cargo", Self::should_build(_config), only_hosts: true, {
        builder.ensure(dist::Cargo { compiler: self.compiler, target: self.target });
        install_cargo(builder, self.compiler.stage, self.target);
    };
    Rls, "rls", Self::should_build(_config), only_hosts: true, {
        if builder.ensure(dist::Rls { compiler: self.compiler, target: self.target }).is_some() ||
            Self::should_install(builder) {
            install_rls(builder, self.compiler.stage, self.target);
        } else {
            builder.info(
                &format!("skipping Install RLS stage{} ({})", self.compiler.stage, self.target),
            );
        }
    };
    Clippy, "clippy", Self::should_build(_config), only_hosts: true, {
        if builder.ensure(dist::Clippy {
            compiler: self.compiler,
            target: self.target,
        }).is_some() || Self::should_install(builder) {
            install_clippy(builder, self.compiler.stage, self.target);
        } else {
            builder.info(
                &format!("skipping Install clippy stage{} ({})", self.compiler.stage, self.target),
            );
        }
    };
    Miri, "miri", Self::should_build(_config), only_hosts: true, {
        if builder.ensure(dist::Miri { compiler: self.compiler, target: self.target }).is_some() ||
            Self::should_install(builder) {
            install_miri(builder, self.compiler.stage, self.target);
        } else {
            builder.info(
                &format!("skipping Install miri stage{} ({})", self.compiler.stage, self.target),
            );
        }
    };
    Rustfmt, "rustfmt", Self::should_build(_config), only_hosts: true, {
        if builder.ensure(dist::Rustfmt {
            compiler: self.compiler,
            target: self.target
        }).is_some() || Self::should_install(builder) {
            install_rustfmt(builder, self.compiler.stage, self.target);
        } else {
            builder.info(
                &format!("skipping Install Rustfmt stage{} ({})", self.compiler.stage, self.target),
            );
        }
    };
    Analysis, "analysis", Self::should_build(_config), only_hosts: false, {
        builder.ensure(dist::Analysis {
            // Find the actual compiler (handling the full bootstrap option) which
            // produced the save-analysis data because that data isn't copied
            // through the sysroot uplifting.
            compiler: builder.compiler_for(builder.top_stage, builder.config.build, self.target),
            target: self.target
        });
        install_analysis(builder, self.compiler.stage, self.target);
    };
    Rustc, "src/librustc", true, only_hosts: true, {
        builder.ensure(dist::Rustc {
            compiler: self.compiler,
        });
        install_rustc(builder, self.compiler.stage, self.target);
    };
);

#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct Src {
    pub stage: u32,
}

impl Step for Src {
    type Output = ();
    const DEFAULT: bool = true;
    const ONLY_HOSTS: bool = true;

    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
        let config = &run.builder.config;
        let cond = config.extended && config.tools.as_ref().map_or(true, |t| t.contains("src"));
        run.path("src").default_condition(cond)
    }

    fn make_run(run: RunConfig<'_>) {
        run.builder.ensure(Src { stage: run.builder.top_stage });
    }

    fn run(self, builder: &Builder<'_>) {
        builder.ensure(dist::Src);
        install_src(builder, self.stage);
    }
}
<|endoftext|>


<commit_before>use super::collect_versions;
use crate::{codegen::general, env::Env, file_saver::save_to_file};
use log::info;
use std::io::{Result, Write};

pub fn generate(env: &Env) {
    info!(
        "Generating sys build script for {}",
        env.config.library_name
    );

    let split_build_rs = env.config.split_build_rs;
    let path = env.config.target_path.join("build.rs");

    if !split_build_rs || !path.exists() {
        info!("Generating file {:?}", path);
        save_to_file(&path, env.config.make_backup, |w| {
            generate_build_script(w, env, split_build_rs)
        });
    }

    if split_build_rs {
        let path = env.config.target_path.join("build_version.rs");
        info!("Generating file {:?}", path);
        save_to_file(&path, env.config.make_backup, |w| {
            generate_build_version(w, env)
        });
    }
}

#[allow(clippy::write_literal)]
fn generate_build_script(w: &mut dyn Write, env: &Env, split_build_rs: bool) -> Result<()> {
    if !split_build_rs {
        general::start_comments(w, &env.config)?;
        writeln!(w)?;
    }
    writeln!(
        w,
        "{}",
        r##"#[cfg(not(feature = "dox"))]
extern crate system_deps;

#[cfg(not(feature = "dox"))]
use std::io::prelude::*;
#[cfg(not(feature = "dox"))]
use std::io;
#[cfg(not(feature = "dox"))]
use std::process;"##
    )?;

    if split_build_rs {
        writeln!(w)?;
        writeln!(w, "mod build_version;")?;
    }

    write!(
        w,
        "{}",
        r##"
#[cfg(feature = "dox")]
fn main() {} // prevent linking libraries to avoid documentation failure

#[cfg(not(feature = "dox"))]
fn main() {
    if let Err(s) = system_deps::Config::new().probe() {
        let _ = writeln!(io::stderr(), "{}", s);
        process::exit(1);
    }
}
"##
    )
}

fn generate_build_version(w: &mut dyn Write, env: &Env) -> Result<()> {
    general::start_comments(w, &env.config)?;
    writeln!(w)?;
    writeln!(w, "pub fn version() -> &'static str {{")?;
    write_version(w, env, false)?;
    writeln!(w, "}}")
}

fn write_version(w: &mut dyn Write, env: &Env, for_let: bool) -> Result<()> {
    let versions = collect_versions(env);

    for (version, lib_version) in versions.iter().rev() {
        write!(
            w,
            "if cfg!({}) {{\n\t\t\"{}\"\n\t}} else ",
            version.to_cfg(),
            lib_version
        )?;
    }
    let end = if for_let { ";" } else { "" };
    writeln!(w, "{{\n\t\t\"{}\"\n\t}}{}", env.config.min_cfg_version, end)
}
<commit_msg>Use `eprintln` for writing to stderr<commit_after>use super::collect_versions;
use crate::{codegen::general, env::Env, file_saver::save_to_file};
use log::info;
use std::io::{Result, Write};

pub fn generate(env: &Env) {
    info!(
        "Generating sys build script for {}",
        env.config.library_name
    );

    let split_build_rs = env.config.split_build_rs;
    let path = env.config.target_path.join("build.rs");

    if !split_build_rs || !path.exists() {
        info!("Generating file {:?}", path);
        save_to_file(&path, env.config.make_backup, |w| {
            generate_build_script(w, env, split_build_rs)
        });
    }

    if split_build_rs {
        let path = env.config.target_path.join("build_version.rs");
        info!("Generating file {:?}", path);
        save_to_file(&path, env.config.make_backup, |w| {
            generate_build_version(w, env)
        });
    }
}

#[allow(clippy::write_literal)]
fn generate_build_script(w: &mut dyn Write, env: &Env, split_build_rs: bool) -> Result<()> {
    if !split_build_rs {
        general::start_comments(w, &env.config)?;
        writeln!(w)?;
    }
    writeln!(
        w,
        "{}",
        r##"#[cfg(not(feature = "dox"))]
extern crate system_deps;

#[cfg(not(feature = "dox"))]
use std::io::prelude::*;
#[cfg(not(feature = "dox"))]
use std::io;
#[cfg(not(feature = "dox"))]
use std::process;"##
    )?;

    if split_build_rs {
        writeln!(w)?;
        writeln!(w, "mod build_version;")?;
    }

    write!(
        w,
        "{}",
        r##"
#[cfg(feature = "dox")]
fn main() {} // prevent linking libraries to avoid documentation failure

#[cfg(not(feature = "dox"))]
fn main() {
    if let Err(s) = system_deps::Config::new().probe() {
        let _ = eprintln!("{}", s);
        process::exit(1);
    }
}
"##
    )
}

fn generate_build_version(w: &mut dyn Write, env: &Env) -> Result<()> {
    general::start_comments(w, &env.config)?;
    writeln!(w)?;
    writeln!(w, "pub fn version() -> &'static str {{")?;
    write_version(w, env, false)?;
    writeln!(w, "}}")
}

fn write_version(w: &mut dyn Write, env: &Env, for_let: bool) -> Result<()> {
    let versions = collect_versions(env);

    for (version, lib_version) in versions.iter().rev() {
        write!(
            w,
            "if cfg!({}) {{\n\t\t\"{}\"\n\t}} else ",
            version.to_cfg(),
            lib_version
        )?;
    }
    let end = if for_let { ";" } else { "" };
    writeln!(w, "{{\n\t\t\"{}\"\n\t}}{}", env.config.min_cfg_version, end)
}
<|endoftext|>


<commit_before>use std::fmt::Debug;
use std::marker::PhantomData;
use super::Alphabet;
use expression::{Expression, Condition, ExpressionError};

#[derive(Debug, Eq, PartialEq)]
pub enum RuleError {
    SymbolMismatch,
    RuleArityMismatch,
    ArityMismatch,
    ConditionFalse,
    ConditionFailed,
    ExprFailed(ExpressionError),
}

pub trait ParametricSymbol: Clone + PartialEq + Debug
{
    type Sym: Alphabet;
    type Param: Clone + Debug + PartialEq;

    fn symbol(&self) -> &Self::Sym;
    fn symbol_mut(&mut self) -> &mut Self::Sym;

    fn params(&self) -> &[Self::Param];
    fn params_mut(&mut self) -> &mut [Self::Param];

    /// Construct a new ParametricSymbol. If the iterator contains a wrong
    /// number of parameters, return None.
    fn new_from_result_iter<I, E>(symbol: Self::Sym, iter: I) -> Option<Result<Self, E>>
        where I: Iterator<Item = Result<Self::Param, E>>;

    fn new_from_iter<I>(symbol: Self::Sym, iter: I) -> Option<Self>
        where I: Iterator<Item = Self::Param>
    {
        match Self::new_from_result_iter::<_, ()>(symbol, iter.map(|i| Ok(i))) {
            Some(Ok(res)) => Some(res),
            Some(Err(())) => panic!(),
            None => None,
        }
    }

    fn new_from_vec(symbol: Self::Sym, vec: Vec<Self::Param>) -> Option<Self> {
        Self::new_from_iter(symbol, vec.into_iter())
    }
}

#[derive(Clone, Debug, PartialEq)]
pub struct PSym<Sym: Alphabet, Param: Clone + Debug + PartialEq> {
    symbol: Sym,
    params: Vec<Param>,
}

impl<Sym: Alphabet, Param: Clone + Debug + PartialEq> ParametricSymbol for PSym<Sym, Param> {
    type Sym = Sym;
    type Param = Param;

    fn symbol(&self) -> &Self::Sym {
        &self.symbol
    }
    fn symbol_mut(&mut self) -> &mut Self::Sym {
        &mut self.symbol
    }
    fn params(&self) -> &[Self::Param] {
        &self.params
    }
    fn params_mut(&mut self) -> &mut [Self::Param] {
        &mut self.params
    }

    fn new_from_result_iter<I, E>(symbol: Self::Sym, iter: I) -> Option<Result<Self, E>>
        where I: Iterator<Item = Result<Self::Param, E>>
    {
        let mut params = Vec::with_capacity(iter.size_hint().0);
        for p in iter {
            match p {
                Ok(p) => params.push(p),
                Err(e) => return Some(Err(e)),
            }
        }
        Some(Ok(PSym {
            symbol: symbol,
            params: params,
        }))
    }
}

#[derive(Debug, PartialEq)]
pub struct PSym1<Sym: Alphabet, Param: Clone + Debug + PartialEq> {
    symbol: Sym,
    params: [Param; 1],
}

impl<Sym: Alphabet, Param: Clone + Debug + PartialEq> Clone for PSym1<Sym, Param> {
    fn clone(&self) -> Self {
        PSym1 {
            symbol: self.symbol.clone(),
            params: [self.params[0].clone()],
        }
    }
}

impl<Sym: Alphabet, Param: Clone + Debug + PartialEq> ParametricSymbol for PSym1<Sym, Param> {
    type Sym = Sym;
    type Param = Param;

    fn symbol(&self) -> &Self::Sym {
        &self.symbol
    }
    fn symbol_mut(&mut self) -> &mut Self::Sym {
        &mut self.symbol
    }
    fn params(&self) -> &[Self::Param] {
        &self.params
    }
    fn params_mut(&mut self) -> &mut [Self::Param] {
        &mut self.params
    }

    fn new_from_result_iter<I, E>(symbol: Self::Sym, mut iter: I) -> Option<Result<Self, E>>
        where I: Iterator<Item = Result<Self::Param, E>>
    {
        let p1 = match iter.next() {
            Some(Ok(p)) => p,
            Some(Err(e)) => return Some(Err(e)),
            None => return None,
        };
        if let Some(_) = iter.next() {
            return None;
        }

        Some(Ok(PSym1 {
            symbol: symbol,
            params: [p1],
        }))
    }
}

#[derive(Debug, PartialEq)]
pub struct PSym2<Sym: Alphabet, Param: Clone + Debug + PartialEq> {
    symbol: Sym,
    params: [Param; 2],
}

impl<Sym: Alphabet, Param: Clone + Debug + PartialEq> Clone for PSym2<Sym, Param> {
    fn clone(&self) -> Self {
        PSym2 {
            symbol: self.symbol.clone(),
            params: [self.params[0].clone(), self.params[1].clone()],
        }
    }
}

impl<Sym: Alphabet, Param: Clone + Debug + PartialEq> ParametricSymbol for PSym2<Sym, Param> {
    type Sym = Sym;
    type Param = Param;

    fn symbol(&self) -> &Self::Sym {
        &self.symbol
    }
    fn symbol_mut(&mut self) -> &mut Self::Sym {
        &mut self.symbol
    }
    fn params(&self) -> &[Self::Param] {
        &self.params
    }
    fn params_mut(&mut self) -> &mut [Self::Param] {
        &mut self.params
    }

    fn new_from_result_iter<I, E>(symbol: Self::Sym, mut iter: I) -> Option<Result<Self, E>>
        where I: Iterator<Item = Result<Self::Param, E>>
    {
        let p1 = match iter.next() {
            Some(Ok(p)) => p,
            Some(Err(e)) => return Some(Err(e)),
            None => return None,
        };
        let p2 = match iter.next() {
            Some(Ok(p)) => p,
            Some(Err(e)) => return Some(Err(e)),
            None => return None,
        };
        if let Some(_) = iter.next() {
            return None;
        }

        Some(Ok(PSym2 {
            symbol: symbol,
            params: [p1, p2],
        }))
    }
}

pub trait ParametricRule: Clone + Debug
{
    type InSym: ParametricSymbol;
    type OutSym: ParametricSymbol;

    fn apply(&self, psym: &Self::OutSym) -> Result<Vec<Self::OutSym>, RuleError>;
}

#[derive(Debug, Clone)]
pub struct PRule<Sym, PS, PS2, C>
    where Sym: Alphabet,
          PS: ParametricSymbol<Sym = Sym, Param = C::Expr>,
          PS2: ParametricSymbol<Sym = Sym, Param = <C::Expr as Expression>::Element>,
          C: Condition
{
    symbol: Sym,
    condition: C,
    production: Vec<PS>,
    arity: usize,
    _marker: PhantomData<PS2>,
}

impl<Sym, PS, PS2, C> PRule<Sym, PS, PS2, C>
    where Sym: Alphabet,
          PS: ParametricSymbol<Sym = Sym, Param = C::Expr>,
          PS2: ParametricSymbol<Sym = Sym, Param = <C::Expr as Expression>::Element>,
          C: Condition
{
    pub fn new(sym: Sym, cond: C, prod: Vec<PS>, arity: usize) -> PRule<Sym, PS, PS2, C> {
        PRule {
            symbol: sym,
            condition: cond,
            production: prod,
            arity: arity,
            _marker: PhantomData,
        }
    }
}

impl<Sym, PS, PS2, C> ParametricRule for PRule<Sym, PS, PS2, C>
    where Sym: Alphabet,
          PS: ParametricSymbol<Sym = Sym, Param = C::Expr>,
          PS2: ParametricSymbol<Sym = Sym, Param = <C::Expr as Expression>::Element>,
          C: Condition
{
    type InSym = PS;
    type OutSym = PS2;

    /// Tries to apply the rule and if applicable, produces a successor.
    fn apply(&self, psym: &PS2) -> Result<Vec<PS2>, RuleError> {
        if self.arity != psym.params().len() {
            Err(RuleError::RuleArityMismatch)
        } else if self.symbol.eq(psym.symbol()) {
            match self.condition.evaluate(psym.params()) {
                Ok(true) => {
                    let mut new_symbol_string = Vec::with_capacity(self.production.len());

                    // evaluate all parameters of all symbols in the production
                    for prod_sym in self.production.iter() {
                        match PS2::new_from_result_iter(prod_sym.symbol().clone(),
                                                        prod_sym.params().iter().map(|expr| {
                                                            expr.evaluate(psym.params())
                                                        })) {
                            Some(Ok(new_sym)) => {
                                new_symbol_string.push(new_sym);
                            }
                            Some(Err(e)) => {
                                return Err(RuleError::ExprFailed(e));
                            }
                            None => {
                                return Err(RuleError::ArityMismatch);
                            }
                        }
                    }

                    Ok(new_symbol_string)
                }
                Ok(false) => Err(RuleError::ConditionFalse),
                _ => Err(RuleError::ConditionFailed),
            }
        } else {
            Err(RuleError::SymbolMismatch)
        }
    }
}

#[test]
fn test_rule_apply() {
    use expression::num_expr::NumExpr;
    use expression::cond::Cond;
    let expr_s = PSym::new_from_vec('P', vec![NumExpr::Const(123u32)]).unwrap();

    let rule = PRule::<_, PSym<_, NumExpr<u32>>, PSym<_, u32>, _>::new('A',
                                                                       Cond::True,
                                                                       vec![expr_s.clone()],
                                                                       1);

    let param_s = PSym::new_from_vec('P', vec![123u32]).unwrap();
    assert_eq!(Err(RuleError::SymbolMismatch), rule.apply(&param_s));

    let param_s = PSym::new_from_vec('A', vec![123u32]).unwrap();
    let result_s = PSym::new_from_vec('P', vec![123u32]).unwrap();
    assert_eq!(Ok(vec![result_s]), rule.apply(&param_s));

    let rule = PRule::<_, PSym<_, NumExpr<u32>>, PSym<_, u32>, _>::new('A',
                                                                       Cond::False,
                                                                       vec![expr_s.clone()],
                                                                       1);
    assert_eq!(Err(RuleError::ConditionFalse), rule.apply(&param_s));
}
<commit_msg>Add ParametricSystem trait<commit_after>use std::fmt::Debug;
use std::marker::PhantomData;
use super::Alphabet;
use expression::{Expression, Condition, ExpressionError};

#[derive(Debug, Eq, PartialEq)]
pub enum RuleError {
    SymbolMismatch,
    RuleArityMismatch,
    ArityMismatch,
    ConditionFalse,
    ConditionFailed,
    ExprFailed(ExpressionError),
}

pub trait ParametricSymbol: Clone + PartialEq + Debug
{
    type Sym: Alphabet;
    type Param: Clone + Debug + PartialEq;

    fn symbol(&self) -> &Self::Sym;
    fn symbol_mut(&mut self) -> &mut Self::Sym;

    fn params(&self) -> &[Self::Param];
    fn params_mut(&mut self) -> &mut [Self::Param];

    /// Construct a new ParametricSymbol. If the iterator contains a wrong
    /// number of parameters, return None.
    fn new_from_result_iter<I, E>(symbol: Self::Sym, iter: I) -> Option<Result<Self, E>>
        where I: Iterator<Item = Result<Self::Param, E>>;

    fn new_from_iter<I>(symbol: Self::Sym, iter: I) -> Option<Self>
        where I: Iterator<Item = Self::Param>
    {
        match Self::new_from_result_iter::<_, ()>(symbol, iter.map(|i| Ok(i))) {
            Some(Ok(res)) => Some(res),
            Some(Err(())) => panic!(),
            None => None,
        }
    }

    fn new_from_vec(symbol: Self::Sym, vec: Vec<Self::Param>) -> Option<Self> {
        Self::new_from_iter(symbol, vec.into_iter())
    }
}

#[derive(Clone, Debug, PartialEq)]
pub struct PSym<Sym: Alphabet, Param: Clone + Debug + PartialEq> {
    symbol: Sym,
    params: Vec<Param>,
}

impl<Sym: Alphabet, Param: Clone + Debug + PartialEq> ParametricSymbol for PSym<Sym, Param> {
    type Sym = Sym;
    type Param = Param;

    fn symbol(&self) -> &Self::Sym {
        &self.symbol
    }
    fn symbol_mut(&mut self) -> &mut Self::Sym {
        &mut self.symbol
    }
    fn params(&self) -> &[Self::Param] {
        &self.params
    }
    fn params_mut(&mut self) -> &mut [Self::Param] {
        &mut self.params
    }

    fn new_from_result_iter<I, E>(symbol: Self::Sym, iter: I) -> Option<Result<Self, E>>
        where I: Iterator<Item = Result<Self::Param, E>>
    {
        let mut params = Vec::with_capacity(iter.size_hint().0);
        for p in iter {
            match p {
                Ok(p) => params.push(p),
                Err(e) => return Some(Err(e)),
            }
        }
        Some(Ok(PSym {
            symbol: symbol,
            params: params,
        }))
    }
}

#[derive(Debug, PartialEq)]
pub struct PSym1<Sym: Alphabet, Param: Clone + Debug + PartialEq> {
    symbol: Sym,
    params: [Param; 1],
}

impl<Sym: Alphabet, Param: Clone + Debug + PartialEq> Clone for PSym1<Sym, Param> {
    fn clone(&self) -> Self {
        PSym1 {
            symbol: self.symbol.clone(),
            params: [self.params[0].clone()],
        }
    }
}

impl<Sym: Alphabet, Param: Clone + Debug + PartialEq> ParametricSymbol for PSym1<Sym, Param> {
    type Sym = Sym;
    type Param = Param;

    fn symbol(&self) -> &Self::Sym {
        &self.symbol
    }
    fn symbol_mut(&mut self) -> &mut Self::Sym {
        &mut self.symbol
    }
    fn params(&self) -> &[Self::Param] {
        &self.params
    }
    fn params_mut(&mut self) -> &mut [Self::Param] {
        &mut self.params
    }

    fn new_from_result_iter<I, E>(symbol: Self::Sym, mut iter: I) -> Option<Result<Self, E>>
        where I: Iterator<Item = Result<Self::Param, E>>
    {
        let p1 = match iter.next() {
            Some(Ok(p)) => p,
            Some(Err(e)) => return Some(Err(e)),
            None => return None,
        };
        if let Some(_) = iter.next() {
            return None;
        }

        Some(Ok(PSym1 {
            symbol: symbol,
            params: [p1],
        }))
    }
}

#[derive(Debug, PartialEq)]
pub struct PSym2<Sym: Alphabet, Param: Clone + Debug + PartialEq> {
    symbol: Sym,
    params: [Param; 2],
}

impl<Sym: Alphabet, Param: Clone + Debug + PartialEq> Clone for PSym2<Sym, Param> {
    fn clone(&self) -> Self {
        PSym2 {
            symbol: self.symbol.clone(),
            params: [self.params[0].clone(), self.params[1].clone()],
        }
    }
}

impl<Sym: Alphabet, Param: Clone + Debug + PartialEq> ParametricSymbol for PSym2<Sym, Param> {
    type Sym = Sym;
    type Param = Param;

    fn symbol(&self) -> &Self::Sym {
        &self.symbol
    }
    fn symbol_mut(&mut self) -> &mut Self::Sym {
        &mut self.symbol
    }
    fn params(&self) -> &[Self::Param] {
        &self.params
    }
    fn params_mut(&mut self) -> &mut [Self::Param] {
        &mut self.params
    }

    fn new_from_result_iter<I, E>(symbol: Self::Sym, mut iter: I) -> Option<Result<Self, E>>
        where I: Iterator<Item = Result<Self::Param, E>>
    {
        let p1 = match iter.next() {
            Some(Ok(p)) => p,
            Some(Err(e)) => return Some(Err(e)),
            None => return None,
        };
        let p2 = match iter.next() {
            Some(Ok(p)) => p,
            Some(Err(e)) => return Some(Err(e)),
            None => return None,
        };
        if let Some(_) = iter.next() {
            return None;
        }

        Some(Ok(PSym2 {
            symbol: symbol,
            params: [p1, p2],
        }))
    }
}

pub trait ParametricRule: Clone + Debug
{
    type InSym: ParametricSymbol;
    type OutSym: ParametricSymbol;

    fn apply(&self, psym: &Self::OutSym) -> Result<Vec<Self::OutSym>, RuleError>;
}

#[derive(Debug, Clone)]
pub struct PRule<Sym, PS, PS2, C>
    where Sym: Alphabet,
          PS: ParametricSymbol<Sym = Sym, Param = C::Expr>,
          PS2: ParametricSymbol<Sym = Sym, Param = <C::Expr as Expression>::Element>,
          C: Condition
{
    symbol: Sym,
    condition: C,
    production: Vec<PS>,
    arity: usize,
    _marker: PhantomData<PS2>,
}

impl<Sym, PS, PS2, C> PRule<Sym, PS, PS2, C>
    where Sym: Alphabet,
          PS: ParametricSymbol<Sym = Sym, Param = C::Expr>,
          PS2: ParametricSymbol<Sym = Sym, Param = <C::Expr as Expression>::Element>,
          C: Condition
{
    pub fn new(sym: Sym, cond: C, prod: Vec<PS>, arity: usize) -> PRule<Sym, PS, PS2, C> {
        PRule {
            symbol: sym,
            condition: cond,
            production: prod,
            arity: arity,
            _marker: PhantomData,
        }
    }
}

impl<Sym, PS, PS2, C> ParametricRule for PRule<Sym, PS, PS2, C>
    where Sym: Alphabet,
          PS: ParametricSymbol<Sym = Sym, Param = C::Expr>,
          PS2: ParametricSymbol<Sym = Sym, Param = <C::Expr as Expression>::Element>,
          C: Condition
{
    type InSym = PS;
    type OutSym = PS2;

    /// Tries to apply the rule and if applicable, produces a successor.
    fn apply(&self, psym: &PS2) -> Result<Vec<PS2>, RuleError> {
        if self.arity != psym.params().len() {
            Err(RuleError::RuleArityMismatch)
        } else if self.symbol.eq(psym.symbol()) {
            match self.condition.evaluate(psym.params()) {
                Ok(true) => {
                    let mut new_symbol_string = Vec::with_capacity(self.production.len());

                    // evaluate all parameters of all symbols in the production
                    for prod_sym in self.production.iter() {
                        match PS2::new_from_result_iter(prod_sym.symbol().clone(),
                                                        prod_sym.params().iter().map(|expr| {
                                                            expr.evaluate(psym.params())
                                                        })) {
                            Some(Ok(new_sym)) => {
                                new_symbol_string.push(new_sym);
                            }
                            Some(Err(e)) => {
                                return Err(RuleError::ExprFailed(e));
                            }
                            None => {
                                return Err(RuleError::ArityMismatch);
                            }
                        }
                    }

                    Ok(new_symbol_string)
                }
                Ok(false) => Err(RuleError::ConditionFalse),
                _ => Err(RuleError::ConditionFailed),
            }
        } else {
            Err(RuleError::SymbolMismatch)
        }
    }
}

#[test]
fn test_rule_apply() {
    use expression::num_expr::NumExpr;
    use expression::cond::Cond;
    let expr_s = PSym::new_from_vec('P', vec![NumExpr::Const(123u32)]).unwrap();

    let rule = PRule::<_, PSym<_, NumExpr<u32>>, PSym<_, u32>, _>::new('A',
                                                                       Cond::True,
                                                                       vec![expr_s.clone()],
                                                                       1);

    let param_s = PSym::new_from_vec('P', vec![123u32]).unwrap();
    assert_eq!(Err(RuleError::SymbolMismatch), rule.apply(&param_s));

    let param_s = PSym::new_from_vec('A', vec![123u32]).unwrap();
    let result_s = PSym::new_from_vec('P', vec![123u32]).unwrap();
    assert_eq!(Ok(vec![result_s]), rule.apply(&param_s));

    let rule = PRule::<_, PSym<_, NumExpr<u32>>, PSym<_, u32>, _>::new('A',
                                                                       Cond::False,
                                                                       vec![expr_s.clone()],
                                                                       1);
    assert_eq!(Err(RuleError::ConditionFalse), rule.apply(&param_s));
}

pub trait ParametricSystem {
    type Rule: ParametricRule;

    fn apply_first_rule(&self, sym: &<Self::Rule as ParametricRule>::OutSym) -> Option<Vec<<Self::Rule as ParametricRule>::OutSym>>;

    /// Apply in parallel the first matching rule to each symbol in the string.
    /// Returns the total number of rule applications.
    fn develop_next(&self, axiom: &Vec<<Self::Rule as ParametricRule>::OutSym>) -> (Vec<<Self::Rule as ParametricRule>::OutSym>, usize) {
        let mut expanded = Vec::new();
        let mut rule_applications = 0;

        for sym in axiom.iter() {
            match self.apply_first_rule(sym) {
                Some(successor) => {
                    expanded.extend(successor);
                    rule_applications += 1;
                    // XXX: Count rule applications of the matching rule.
                }

                None => {
                    expanded.push(sym.clone());
                }
            }
        }

        (expanded, rule_applications)
    }

    /// Develop the system starting with `axiom` up to `max_iterations`. Return iteration count.
    fn develop(&self,
               axiom: Vec<<Self::Rule as ParametricRule>::OutSym>,
               max_iterations: usize)
               -> (Vec<<Self::Rule as ParametricRule>::OutSym>, usize) {
        let mut current = axiom;

        for iter in 0..max_iterations {
            let (next, rule_applications) = self.develop_next(&current);
            if rule_applications == 0 {
                return (current, iter);
            }
            current = next;
        }
        return (current, max_iterations);
    }
}
<|endoftext|>


<commit_before>use std::cmp::Ordering;
use std::mem;

#[derive(PartialEq, Eq)]
enum Color {
    Red,
    Black,
}

pub struct RBTree {
    root: Link,
}

struct Link(Option<Box<Node>>);

struct Node {
    key: i32,
    val: i32,
    color: Color,
    left: Link,
    right: Link,
}

impl RBTree {

    pub fn new() -> Self {
        RBTree { root: Link(None) }
    }

    pub fn get(&self, key: i32) -> Option<i32> {
        self.root.get(key)
    }

    pub fn insert(&mut self, key: i32, value: i32) -> Option<i32> {
        let prev = self.root.insert(key, value);
        let Link(ref mut node) = self.root;
        node.as_mut().unwrap().color = Color::Black;
        prev
    }
}

fn new_leaf(key: i32, val: i32) -> Option<Box<Node>> {
    Some(Box::new(Node::new(key, val)))
}

impl Node {

    fn new(key: i32, val: i32) -> Self {
        Node {
            key: key,
            val: val,
            color: Color::Red,
            left: Link(None),
            right: Link(None),
        }
    }
}

impl Link {

    fn is_red(&self) -> bool {
        let Link(ref node_option) = *self;
        match *node_option {
            None => false,
            Some(ref node) => node.color == Color::Red,
        }
    }

    fn get(&self, key: i32) -> Option<i32> {
        let Link(ref node_option) = *self;
        match *node_option {
            None => None,
            Some(ref node) => match key.cmp(&node.key) {
                Ordering::Equal => Some(node.val),
                Ordering::Less => node.left.get(key),
                Ordering::Greater => node.right.get(key),
            }
        }
    }

    fn insert(&mut self, key: i32, value: i32) -> Option<i32> {
        let Link(ref mut node_option) = *self;
        match *node_option {
            None => {
                *node_option = new_leaf(key, value);
                None
            },
            Some(ref mut node) => {
                match key.cmp(&node.key) {
                    Ordering::Equal => {
                        let prev = node.val;
                        node.val = value;
                        Some(prev)
                    },
                    Ordering::Less => node.left.insert(key, value),
                    Ordering::Greater => node.right.insert(key, value),
                }
            }
        }
    }
}

#[test]
fn basic_construction() {
    let mut tree = RBTree::new();
    assert_eq!(tree.get(0), None);
    assert_eq!(tree.insert(0, 1), None);
    assert_eq!(tree.insert(0, 2), Some(1));
    assert_eq!(tree.get(0), Some(2));
}
<commit_msg>Basic refactoring of red black tree.<commit_after>use std::cmp::Ordering;
use std::mem;

#[derive(PartialEq, Eq)]
enum Color {
    Red,
    Black,
}

type Link = Box<Node>;
type LinkOrEmpty = Option<Link>;

pub struct RBTree {
    root: LinkOrEmpty,
}

struct Node {
    key: i32,
    val: i32,
    color: Color,
    left: LinkOrEmpty,
    right: LinkOrEmpty,
}

impl RBTree {

    pub fn new() -> Self {
        RBTree { root: None }
    }

    pub fn get(&self, key: i32) -> Option<i32> {
        self.root.get(key)
    }

    pub fn insert(&mut self, key: i32, value: i32) -> Option<i32> {
        let prev = self.root.insert(key, value);
        self.root.as_mut().unwrap().color = Color::Black;
        prev
    }

}

fn new_leaf(key: i32, val: i32) -> LinkOrEmpty {
    Some(Box::new(Node::new(key, val)))
}

impl Node {

    fn new(key: i32, val: i32) -> Self {
        Node {
            key: key,
            val: val,
            color: Color::Red,
            left: None,
            right: None,
        }
    }

}

trait BoxNode {
    fn left_rotate(&mut self) -> ();
}

impl BoxNode for Link {

    fn left_rotate(&mut self) -> () {
        let mut y = self.right.take().unwrap();
        mem::swap(&mut self.right, &mut y.left);
        mem::swap(self, &mut y.left.take().unwrap());
    }
}

trait PtrNode {
    fn get(&self, key: i32) -> Option<i32>;
    fn insert(&mut self, key: i32, val: i32) -> Option<i32>;
}

impl PtrNode for LinkOrEmpty {

    fn get(&self, key: i32) -> Option<i32> {
        match *self {
            None => None,
            Some(ref node) => match key.cmp(&node.key) {
                Ordering::Equal => Some(node.val),
                Ordering::Less => node.left.get(key),
                Ordering::Greater => node.right.get(key)
            }
        }
    }

    fn insert(&mut self, key: i32, value: i32) -> Option<i32> {
        match *self {
            None => {
                *self = new_leaf(key, value);
                None
            },
            Some(ref mut node) => {
                match key.cmp(&node.key) {
                    Ordering::Equal => {
                        let prev = node.val;
                        node.val = value;
                        Some(prev)
                    },
                    Ordering::Less => node.left.insert(key, value),
                    Ordering::Greater => node.right.insert(key, value),
                }
            }
        }
    }

}

#[test]
fn basic_construction() {
    let mut tree = RBTree::new();
    assert_eq!(tree.get(0), None);
    assert_eq!(tree.insert(0, 1), None);
    assert_eq!(tree.insert(0, 2), Some(1));
    assert_eq!(tree.get(0), Some(2));
 }
<|endoftext|>


<commit_before>extern crate flate2;
extern crate std;
extern crate tar;

use std::io::Read;

#[derive(Debug, Default, Clone)]
pub struct Desc {
    groups: Vec<String>,
    license: Vec<String>,
    replaces: Vec<String>,
    filename: String,
    name: String,
    base: String,
    version: String,
    desc: String,
    csize: u64,
    isize: u64,
    md5sum: String,
    sha256sum: String,
    pgpsig: String,
    url: String,
    arch: String,
    builddate: u64,
    packager: String,

    // These fields are once stored in depends file
    // https://git.archlinux.org/pacman.git/commit/?id=b520c6312ff0ffec864576b5218f1638fae1e18b
    conflicts: Vec<String>,
    provides: Vec<String>,
    depends: Vec<String>,
    makedepends: Vec<String>,
    checkdepends: Vec<String>,
    optdepends: Vec<String>,
}

#[derive(Clone)]
pub struct PackageEntry {
    pub desc: Desc,
    pub files: Vec<String>,
}

#[derive(Clone)]
pub struct Repository<'a> {
    path: std::path::PathBuf,
    signer: Option<&'a super::signer::Signer<'a>>,
    entries: std::collections::HashMap<String, PackageEntry>,
}

impl<'a> Repository<'a> {
    pub fn new(path: std::path::PathBuf,
               signer: Option<&'a super::signer::Signer<'a>>)
               -> Repository {
        return Repository {
            path: path,
            signer: signer,
            entries: std::collections::HashMap::new(),
        };
    }

    pub fn load(&mut self) {
        match std::fs::File::open(&self.path) {
            Ok(file) => {
                let gz_reader = flate2::read::GzDecoder::new(file).unwrap();
                let mut tar_reader = tar::Archive::new(gz_reader);
                let mut desc_entries = std::collections::HashMap::new();
                let mut files_entries = std::collections::HashMap::new();
                for entry_result in tar_reader.entries().unwrap() {
                    let mut entry = entry_result.unwrap();
                    let pathbuf = entry.path().unwrap().into_owned();
                    let pathname = pathbuf.to_str().unwrap();
                    match entry.header().entry_type() {
                        tar::EntryType::Regular => {
                            let splitn: Vec<&str> = pathname.splitn(2, '/').collect();
                            if splitn.len() == 2 {
                                let mut body = String::new();
                                entry.read_to_string(&mut body).unwrap();
                                match splitn[1] {
                                    "desc" => {
                                        desc_entries.insert(splitn[0].to_owned(), parse_desc(&body));
                                    }
                                    "depends" => {
                                        // old format
                                    }
                                    "files" => {
                                        files_entries.insert(splitn[0].to_owned(), parse_files(&body));
                                    }
                                    _ => {
                                        panic!("Unknown pathname: {}", pathname);
                                    }
                                }
                            } else {
                                panic!("Invalid pathname entry: {}", pathname);
                            }
                        }
                        tar::EntryType::Directory => {}
                        _ => {
                            panic!("Unknown file type: {}", pathname);
                        }
                    }
                }

                for (_, desc) in desc_entries.into_iter() {
                    let files = files_entries.remove(&desc.name).unwrap_or(vec![]);
                    self.entries.insert(desc.name.to_owned(),
                                        PackageEntry {
                                            desc: desc,
                                            files: files,
                                        });
                }
            }
            Err(e) => {
                if e.kind() != std::io::ErrorKind::NotFound {
                    panic!("{:?}", e);
                }
            }
        }
    }

    pub fn add(&mut self, package: &super::package::Package) {
        let desc = Desc {
            groups: package.groups().to_owned(),
            license: package.license().to_owned(),
            replaces: package.replaces().to_owned(),
            filename: package.filename().to_owned(),
            name: package.pkgname().to_owned(),
            base: package.pkgbase().to_owned(),
            version: package.pkgver().to_owned(),
            desc: package.pkgdesc().to_owned(),
            csize: package.csize(),
            isize: package.isize(),
            md5sum: package.md5sum().to_owned(),
            sha256sum: package.sha256sum().to_owned(),
            pgpsig: package.pgpsig().to_owned(),
            url: package.url().to_owned(),
            arch: package.arch().to_owned(),
            builddate: package.builddate(),
            packager: package.packager().to_owned(),
            conflicts: package.conflicts().to_owned(),
            provides: package.provides().to_owned(),
            depends: package.depends().to_owned(),
            makedepends: package.makedepends().to_owned(),
            checkdepends: package.checkdepends().to_owned(),
            optdepends: package.optdepends().to_owned(),
        };
        self.entries.insert(desc.name.to_owned(),
                            PackageEntry {
                                desc: desc,
                                files: package.files().to_owned(),
                            });
    }

    pub fn remove(&mut self, package_name: &str) {
        self.entries.remove(package_name);
    }

    pub fn save(&self, include_files: bool) {
        let mut tmp_path = self.path.clone().into_os_string();
        tmp_path.push(".progress");
        let file = std::fs::File::create(&tmp_path).unwrap();
        let gz_writer = flate2::write::GzEncoder::new(file, flate2::Compression::Default);
        let mut builder = tar::Builder::new(gz_writer);
        for (_, package_entry) in self.entries.iter() {
            let pathbuf = std::path::PathBuf::from(format!("{}-{}/",
                                                           package_entry.desc.name,
                                                           package_entry.desc.version));
            {
                let mut dir_header = tar::Header::new_gnu();
                dir_header.set_entry_type(tar::EntryType::Directory);
                dir_header.set_path(&pathbuf).unwrap();
                dir_header.set_mode(0o755);
                dir_header.set_size(0);
                dir_header.set_cksum();
                builder.append(&dir_header, std::io::empty()).unwrap();
            }
            {
                let mut desc_header = tar::Header::new_gnu();
                desc_header.set_entry_type(tar::EntryType::Regular);
                desc_header.set_path(pathbuf.join("desc")).unwrap();
                desc_header.set_mode(0o644);
                let desc_str = into_desc_file(package_entry);
                let desc_bytes = desc_str.as_bytes();
                desc_header.set_size(desc_bytes.len() as u64);
                desc_header.set_cksum();
                builder.append(&desc_header, desc_bytes).unwrap();
            }
            if include_files {
                let mut files_header = tar::Header::new_gnu();
                files_header.set_entry_type(tar::EntryType::Regular);
                files_header.set_path(pathbuf.join("files")).unwrap();
                files_header.set_mode(0o644);
                let files_str = into_files_file(&package_entry.files);
                let files_bytes = files_str.as_bytes();
                files_header.set_size(files_bytes.len() as u64);
                files_header.set_cksum();
                builder.append(&files_header, files_bytes).unwrap();
            }
        }
        let gz_writer = builder.into_inner().unwrap();
        gz_writer.finish().unwrap();

        if let Some(ref signer) = self.signer {
            let mut sig_path = self.path.clone().into_os_string();
            sig_path.push(".sig");
            signer.sign(&tmp_path, sig_path);
        }

        std::fs::rename(&tmp_path, &self.path).unwrap();
    }
}

fn parse_desc(body: &str) -> Desc {
    let mut desc = Desc::default();
    for (key, val) in each_entry(body) {
        match key {
            "GROUPS" => {
                desc.groups.push(val.to_owned());
            }
            "REPLACES" => {
                desc.replaces.push(val.to_owned());
            }
            "FILENAME" => {
                desc.filename = val.to_owned();
            }
            "NAME" => {
                desc.name = val.to_owned();
            }
            "BASE" => {
                desc.base = val.to_owned();
            }
            "VERSION" => {
                desc.version = val.to_owned();
            }
            "DESC" => {
                desc.desc = val.to_owned();
            }
            "CSIZE" => {
                desc.csize = val.parse().unwrap();
            }
            "ISIZE" => {
                desc.isize = val.parse().unwrap();
            }
            "MD5SUM" => {
                desc.md5sum = val.to_owned();
            }
            "SHA256SUM" => {
                desc.sha256sum = val.to_owned();
            }
            "PGPSIG" => {
                desc.pgpsig = val.to_owned();
            }
            "URL" => {
                desc.url = val.to_owned();
            }
            "LICENSE" => {
                desc.license.push(val.to_owned());
            }
            "ARCH" => {
                desc.arch = val.to_owned();
            }
            "BUILDDATE" => {
                desc.builddate = val.parse().unwrap();
            }
            "PACKAGER" => {
                desc.packager = val.to_owned();
            }
            "CONFLICTS" => {
                desc.conflicts.push(val.to_owned());
            }
            "PROVIDES" => {
                desc.provides.push(val.to_owned());
            }
            "DEPENDS" => {
                desc.depends.push(val.to_owned());
            }
            "MAKEDEPENDS" => {
                desc.makedepends.push(val.to_owned());
            }
            "CHECKDEPENDS" => {
                desc.checkdepends.push(val.to_owned());
            }
            "OPTDEPENDS" => {
                desc.optdepends.push(val.to_owned());
            }
            _ => {
                panic!("Unknown desc entry: {}", key);
            }
        }
    }
    return desc;
}

struct EachEntry<'a> {
    key: &'a str,
    lines: std::str::Lines<'a>,
}

impl<'a> Iterator for EachEntry<'a> {
    type Item = (&'a str, &'a str);

    fn next(&mut self) -> Option<Self::Item> {
        while let Some(line) = self.lines.next() {
            let line = line.trim();
            if line.starts_with('%') && line.ends_with('%') {
                self.key = &line[1..line.len() - 1];
            } else if line.is_empty() {
                self.key = "";
            } else {
                return Some((self.key, line));
            }
        }
        return None;
    }
}

fn each_entry(body: &str) -> EachEntry {
    EachEntry {
        key: "",
        lines: body.lines(),
    }
}

fn into_desc_file(package_entry: &PackageEntry) -> String {
    let mut buf = String::new();
    let ref desc = package_entry.desc;
    desc_write_array(&mut buf, "GROUPS", &desc.groups);
    desc_write_array(&mut buf, "REPLACES", &desc.replaces);
    desc_write_string(&mut buf, "FILENAME", &desc.filename);
    desc_write_string(&mut buf, "NAME", &desc.name);
    desc_write_string(&mut buf, "BASE", &desc.base);
    desc_write_string(&mut buf, "VERSION", &desc.version);
    desc_write_string(&mut buf, "DESC", &desc.desc);
    desc_write_u64(&mut buf, "CSIZE", desc.csize);
    desc_write_u64(&mut buf, "ISIZE", desc.isize);
    desc_write_string(&mut buf, "MD5SUM", &desc.md5sum);
    desc_write_string(&mut buf, "SHA256SUM", &desc.sha256sum);
    desc_write_string(&mut buf, "PGPSIG", &desc.pgpsig);
    desc_write_string(&mut buf, "URL", &desc.url);
    desc_write_array(&mut buf, "LICENSE", &desc.license);
    desc_write_string(&mut buf, "ARCH", &desc.arch);
    desc_write_u64(&mut buf, "BUILDDATE", desc.builddate);
    desc_write_string(&mut buf, "PACKAGER", &desc.packager);
    desc_write_array(&mut buf, "CONFLICTS", &desc.conflicts);
    desc_write_array(&mut buf, "PROVIDES", &desc.provides);
    desc_write_array(&mut buf, "DEPENDS", &desc.depends);
    desc_write_array(&mut buf, "MAKEDEPENDS", &desc.makedepends);
    desc_write_array(&mut buf, "CHECKDEPENDS", &desc.checkdepends);
    desc_write_array(&mut buf, "OPTDEPENDS", &desc.optdepends);
    return buf;
}

fn desc_write_array(buf: &mut String, key: &str, xs: &Vec<String>) {
    if !xs.is_empty() {
        buf.push_str("%");
        buf.push_str(key);
        buf.push_str("%\n");
        for x in xs {
            buf.push_str(&x);
            buf.push_str("\n");
        }
        buf.push_str("\n");
    }
}

fn desc_write_string(buf: &mut String, key: &str, val: &str) {
    if !val.is_empty() {
        buf.push_str("%");
        buf.push_str(key);
        buf.push_str("%\n");
        buf.push_str(val);
        buf.push_str("\n\n");
    }
}

fn desc_write_u64(buf: &mut String, key: &str, val: u64) {
    if val != 0 {
        buf.push_str("%");
        buf.push_str(key);
        buf.push_str("%\n");
        buf.push_str(&format!("{}", val));
        buf.push_str("\n\n");
    }
}

fn parse_files(body: &str) -> Vec<String> {
    let mut iter = body.lines();

    if let Some("%FILES%") = iter.next() {
        let mut files = vec![];
        for line in iter {
            files.push(line.to_owned());
        }
        return files;
    } else {
        panic!("Empty files file");
    }
}

fn into_files_file(files: &Vec<String>) -> String {
    let mut buf = String::new();
    buf.push_str("%FILES%\n");
    for file in files {
        buf.push_str(file);
        buf.push_str("\n");
    }
    return buf;
}
<commit_msg>Unindent<commit_after>extern crate flate2;
extern crate std;
extern crate tar;

use std::io::Read;

#[derive(Debug, Default, Clone)]
pub struct Desc {
    groups: Vec<String>,
    license: Vec<String>,
    replaces: Vec<String>,
    filename: String,
    name: String,
    base: String,
    version: String,
    desc: String,
    csize: u64,
    isize: u64,
    md5sum: String,
    sha256sum: String,
    pgpsig: String,
    url: String,
    arch: String,
    builddate: u64,
    packager: String,

    // These fields are once stored in depends file
    // https://git.archlinux.org/pacman.git/commit/?id=b520c6312ff0ffec864576b5218f1638fae1e18b
    conflicts: Vec<String>,
    provides: Vec<String>,
    depends: Vec<String>,
    makedepends: Vec<String>,
    checkdepends: Vec<String>,
    optdepends: Vec<String>,
}

#[derive(Clone)]
pub struct PackageEntry {
    pub desc: Desc,
    pub files: Vec<String>,
}

#[derive(Clone)]
pub struct Repository<'a> {
    path: std::path::PathBuf,
    signer: Option<&'a super::signer::Signer<'a>>,
    entries: std::collections::HashMap<String, PackageEntry>,
}

impl<'a> Repository<'a> {
    pub fn new(path: std::path::PathBuf,
               signer: Option<&'a super::signer::Signer<'a>>)
               -> Repository {
        return Repository {
            path: path,
            signer: signer,
            entries: std::collections::HashMap::new(),
        };
    }

    pub fn load(&mut self) {
        match std::fs::File::open(&self.path) {
            Ok(file) => self.load_from_file(file),
            Err(e) => {
                if e.kind() != std::io::ErrorKind::NotFound {
                    panic!("{:?}", e);
                }
            }
        }
    }

    fn load_from_file(&mut self, file: std::fs::File) {
        let gz_reader = flate2::read::GzDecoder::new(file).unwrap();
        let mut tar_reader = tar::Archive::new(gz_reader);
        let mut desc_entries = std::collections::HashMap::new();
        let mut files_entries = std::collections::HashMap::new();
        for entry_result in tar_reader.entries().unwrap() {
            let mut entry = entry_result.unwrap();
            let pathbuf = entry.path().unwrap().into_owned();
            let pathname = pathbuf.to_str().unwrap();
            match entry.header().entry_type() {
                tar::EntryType::Regular => {
                    let splitn: Vec<&str> = pathname.splitn(2, '/').collect();
                    if splitn.len() == 2 {
                        let mut body = String::new();
                        entry.read_to_string(&mut body).unwrap();
                        match splitn[1] {
                            "desc" => {
                                desc_entries.insert(splitn[0].to_owned(), parse_desc(&body));
                            }
                            "depends" => {
                                // old format
                            }
                            "files" => {
                                files_entries.insert(splitn[0].to_owned(), parse_files(&body));
                            }
                            _ => {
                                panic!("Unknown pathname: {}", pathname);
                            }
                        }
                    } else {
                        panic!("Invalid pathname entry: {}", pathname);
                    }
                }
                tar::EntryType::Directory => {}
                _ => {
                    panic!("Unknown file type: {}", pathname);
                }
            }
        }

        for (_, desc) in desc_entries.into_iter() {
            let files = files_entries.remove(&desc.name).unwrap_or(vec![]);
            self.entries.insert(desc.name.to_owned(),
                                PackageEntry {
                                    desc: desc,
                                    files: files,
                                });
        }
    }

    pub fn add(&mut self, package: &super::package::Package) {
        let desc = Desc {
            groups: package.groups().to_owned(),
            license: package.license().to_owned(),
            replaces: package.replaces().to_owned(),
            filename: package.filename().to_owned(),
            name: package.pkgname().to_owned(),
            base: package.pkgbase().to_owned(),
            version: package.pkgver().to_owned(),
            desc: package.pkgdesc().to_owned(),
            csize: package.csize(),
            isize: package.isize(),
            md5sum: package.md5sum().to_owned(),
            sha256sum: package.sha256sum().to_owned(),
            pgpsig: package.pgpsig().to_owned(),
            url: package.url().to_owned(),
            arch: package.arch().to_owned(),
            builddate: package.builddate(),
            packager: package.packager().to_owned(),
            conflicts: package.conflicts().to_owned(),
            provides: package.provides().to_owned(),
            depends: package.depends().to_owned(),
            makedepends: package.makedepends().to_owned(),
            checkdepends: package.checkdepends().to_owned(),
            optdepends: package.optdepends().to_owned(),
        };
        self.entries.insert(desc.name.to_owned(),
                            PackageEntry {
                                desc: desc,
                                files: package.files().to_owned(),
                            });
    }

    pub fn remove(&mut self, package_name: &str) {
        self.entries.remove(package_name);
    }

    pub fn save(&self, include_files: bool) {
        let mut tmp_path = self.path.clone().into_os_string();
        tmp_path.push(".progress");
        let file = std::fs::File::create(&tmp_path).unwrap();
        let gz_writer = flate2::write::GzEncoder::new(file, flate2::Compression::Default);
        let mut builder = tar::Builder::new(gz_writer);
        for (_, package_entry) in self.entries.iter() {
            let pathbuf = std::path::PathBuf::from(format!("{}-{}/",
                                                           package_entry.desc.name,
                                                           package_entry.desc.version));
            {
                let mut dir_header = tar::Header::new_gnu();
                dir_header.set_entry_type(tar::EntryType::Directory);
                dir_header.set_path(&pathbuf).unwrap();
                dir_header.set_mode(0o755);
                dir_header.set_size(0);
                dir_header.set_cksum();
                builder.append(&dir_header, std::io::empty()).unwrap();
            }
            {
                let mut desc_header = tar::Header::new_gnu();
                desc_header.set_entry_type(tar::EntryType::Regular);
                desc_header.set_path(pathbuf.join("desc")).unwrap();
                desc_header.set_mode(0o644);
                let desc_str = into_desc_file(package_entry);
                let desc_bytes = desc_str.as_bytes();
                desc_header.set_size(desc_bytes.len() as u64);
                desc_header.set_cksum();
                builder.append(&desc_header, desc_bytes).unwrap();
            }
            if include_files {
                let mut files_header = tar::Header::new_gnu();
                files_header.set_entry_type(tar::EntryType::Regular);
                files_header.set_path(pathbuf.join("files")).unwrap();
                files_header.set_mode(0o644);
                let files_str = into_files_file(&package_entry.files);
                let files_bytes = files_str.as_bytes();
                files_header.set_size(files_bytes.len() as u64);
                files_header.set_cksum();
                builder.append(&files_header, files_bytes).unwrap();
            }
        }
        let gz_writer = builder.into_inner().unwrap();
        gz_writer.finish().unwrap();

        if let Some(ref signer) = self.signer {
            let mut sig_path = self.path.clone().into_os_string();
            sig_path.push(".sig");
            signer.sign(&tmp_path, sig_path);
        }

        std::fs::rename(&tmp_path, &self.path).unwrap();
    }
}

fn parse_desc(body: &str) -> Desc {
    let mut desc = Desc::default();
    for (key, val) in each_entry(body) {
        match key {
            "GROUPS" => {
                desc.groups.push(val.to_owned());
            }
            "REPLACES" => {
                desc.replaces.push(val.to_owned());
            }
            "FILENAME" => {
                desc.filename = val.to_owned();
            }
            "NAME" => {
                desc.name = val.to_owned();
            }
            "BASE" => {
                desc.base = val.to_owned();
            }
            "VERSION" => {
                desc.version = val.to_owned();
            }
            "DESC" => {
                desc.desc = val.to_owned();
            }
            "CSIZE" => {
                desc.csize = val.parse().unwrap();
            }
            "ISIZE" => {
                desc.isize = val.parse().unwrap();
            }
            "MD5SUM" => {
                desc.md5sum = val.to_owned();
            }
            "SHA256SUM" => {
                desc.sha256sum = val.to_owned();
            }
            "PGPSIG" => {
                desc.pgpsig = val.to_owned();
            }
            "URL" => {
                desc.url = val.to_owned();
            }
            "LICENSE" => {
                desc.license.push(val.to_owned());
            }
            "ARCH" => {
                desc.arch = val.to_owned();
            }
            "BUILDDATE" => {
                desc.builddate = val.parse().unwrap();
            }
            "PACKAGER" => {
                desc.packager = val.to_owned();
            }
            "CONFLICTS" => {
                desc.conflicts.push(val.to_owned());
            }
            "PROVIDES" => {
                desc.provides.push(val.to_owned());
            }
            "DEPENDS" => {
                desc.depends.push(val.to_owned());
            }
            "MAKEDEPENDS" => {
                desc.makedepends.push(val.to_owned());
            }
            "CHECKDEPENDS" => {
                desc.checkdepends.push(val.to_owned());
            }
            "OPTDEPENDS" => {
                desc.optdepends.push(val.to_owned());
            }
            _ => {
                panic!("Unknown desc entry: {}", key);
            }
        }
    }
    return desc;
}

struct EachEntry<'a> {
    key: &'a str,
    lines: std::str::Lines<'a>,
}

impl<'a> Iterator for EachEntry<'a> {
    type Item = (&'a str, &'a str);

    fn next(&mut self) -> Option<Self::Item> {
        while let Some(line) = self.lines.next() {
            let line = line.trim();
            if line.starts_with('%') && line.ends_with('%') {
                self.key = &line[1..line.len() - 1];
            } else if line.is_empty() {
                self.key = "";
            } else {
                return Some((self.key, line));
            }
        }
        return None;
    }
}

fn each_entry(body: &str) -> EachEntry {
    EachEntry {
        key: "",
        lines: body.lines(),
    }
}

fn into_desc_file(package_entry: &PackageEntry) -> String {
    let mut buf = String::new();
    let ref desc = package_entry.desc;
    desc_write_array(&mut buf, "GROUPS", &desc.groups);
    desc_write_array(&mut buf, "REPLACES", &desc.replaces);
    desc_write_string(&mut buf, "FILENAME", &desc.filename);
    desc_write_string(&mut buf, "NAME", &desc.name);
    desc_write_string(&mut buf, "BASE", &desc.base);
    desc_write_string(&mut buf, "VERSION", &desc.version);
    desc_write_string(&mut buf, "DESC", &desc.desc);
    desc_write_u64(&mut buf, "CSIZE", desc.csize);
    desc_write_u64(&mut buf, "ISIZE", desc.isize);
    desc_write_string(&mut buf, "MD5SUM", &desc.md5sum);
    desc_write_string(&mut buf, "SHA256SUM", &desc.sha256sum);
    desc_write_string(&mut buf, "PGPSIG", &desc.pgpsig);
    desc_write_string(&mut buf, "URL", &desc.url);
    desc_write_array(&mut buf, "LICENSE", &desc.license);
    desc_write_string(&mut buf, "ARCH", &desc.arch);
    desc_write_u64(&mut buf, "BUILDDATE", desc.builddate);
    desc_write_string(&mut buf, "PACKAGER", &desc.packager);
    desc_write_array(&mut buf, "CONFLICTS", &desc.conflicts);
    desc_write_array(&mut buf, "PROVIDES", &desc.provides);
    desc_write_array(&mut buf, "DEPENDS", &desc.depends);
    desc_write_array(&mut buf, "MAKEDEPENDS", &desc.makedepends);
    desc_write_array(&mut buf, "CHECKDEPENDS", &desc.checkdepends);
    desc_write_array(&mut buf, "OPTDEPENDS", &desc.optdepends);
    return buf;
}

fn desc_write_array(buf: &mut String, key: &str, xs: &Vec<String>) {
    if !xs.is_empty() {
        buf.push_str("%");
        buf.push_str(key);
        buf.push_str("%\n");
        for x in xs {
            buf.push_str(&x);
            buf.push_str("\n");
        }
        buf.push_str("\n");
    }
}

fn desc_write_string(buf: &mut String, key: &str, val: &str) {
    if !val.is_empty() {
        buf.push_str("%");
        buf.push_str(key);
        buf.push_str("%\n");
        buf.push_str(val);
        buf.push_str("\n\n");
    }
}

fn desc_write_u64(buf: &mut String, key: &str, val: u64) {
    if val != 0 {
        buf.push_str("%");
        buf.push_str(key);
        buf.push_str("%\n");
        buf.push_str(&format!("{}", val));
        buf.push_str("\n\n");
    }
}

fn parse_files(body: &str) -> Vec<String> {
    let mut iter = body.lines();

    if let Some("%FILES%") = iter.next() {
        let mut files = vec![];
        for line in iter {
            files.push(line.to_owned());
        }
        return files;
    } else {
        panic!("Empty files file");
    }
}

fn into_files_file(files: &Vec<String>) -> String {
    let mut buf = String::new();
    buf.push_str("%FILES%\n");
    for file in files {
        buf.push_str(file);
        buf.push_str("\n");
    }
    return buf;
}
<|endoftext|>