<commit_before>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

//! Defines common code used in execution plans

use std::fs;
use std::fs::metadata;
use std::sync::Arc;
use std::task::{Context, Poll};

use super::{RecordBatchStream, SendableRecordBatchStream};
use crate::error::{DataFusionError, Result};

use array::{
    BooleanArray, Float32Array, Float64Array, Int16Array, Int32Array, Int64Array,
    Int8Array, LargeStringArray, StringArray, UInt16Array, UInt32Array, UInt64Array,
    UInt8Array,
};
use arrow::datatypes::{DataType, SchemaRef};
use arrow::error::Result as ArrowResult;
use arrow::record_batch::RecordBatch;
use arrow::{
    array::{self, ArrayRef},
    datatypes::Schema,
};
use futures::{Stream, TryStreamExt};

/// Stream of record batches
pub struct SizedRecordBatchStream {
    schema: SchemaRef,
    batches: Vec<Arc<RecordBatch>>,
    index: usize,
}

impl SizedRecordBatchStream {
    /// Create a new RecordBatchIterator
    pub fn new(schema: SchemaRef, batches: Vec<Arc<RecordBatch>>) -> Self {
        SizedRecordBatchStream {
            schema,
            index: 0,
            batches,
        }
    }
}

impl Stream for SizedRecordBatchStream {
    type Item = ArrowResult<RecordBatch>;

    fn poll_next(
        mut self: std::pin::Pin<&mut Self>,
        _: &mut Context<'_>,
    ) -> Poll<Option<Self::Item>> {
        Poll::Ready(if self.index < self.batches.len() {
            self.index += 1;
            Some(Ok(self.batches[self.index - 1].as_ref().clone()))
        } else {
            None
        })
    }
}

impl RecordBatchStream for SizedRecordBatchStream {
    fn schema(&self) -> SchemaRef {
        self.schema.clone()
    }
}

/// Create a vector of record batches from a stream
pub async fn collect(stream: SendableRecordBatchStream) -> Result<Vec<RecordBatch>> {
    stream
        .try_collect::<Vec<_>>()
        .await
        .map_err(DataFusionError::from)
}

/// Recursively build a list of files in a directory with a given extension
pub fn build_file_list(dir: &str, filenames: &mut Vec<String>, ext: &str) -> Result<()> {
    let metadata = metadata(dir)?;
    if metadata.is_file() {
        if dir.ends_with(ext) {
            filenames.push(dir.to_string());
        }
    } else {
        for entry in fs::read_dir(dir)? {
            let entry = entry?;
            let path = entry.path();
            if let Some(path_name) = path.to_str() {
                if path.is_dir() {
                    build_file_list(path_name, filenames, ext)?;
                } else if path_name.ends_with(ext) {
                    filenames.push(path_name.to_string());
                }
            } else {
                return Err(DataFusionError::Plan("Invalid path".to_string()));
            }
        }
    }
    Ok(())
}

/// creates an empty record batch.
pub fn create_batch_empty(schema: &Schema) -> ArrowResult<RecordBatch> {
    let columns = schema
        .fields()
        .iter()
        .map(|f| match f.data_type() {
            DataType::Float32 => {
                Ok(Arc::new(Float32Array::from(vec![] as Vec<f32>)) as ArrayRef)
            }
            DataType::Float64 => {
                Ok(Arc::new(Float64Array::from(vec![] as Vec<f64>)) as ArrayRef)
            }
            DataType::Int64 => {
                Ok(Arc::new(Int64Array::from(vec![] as Vec<i64>)) as ArrayRef)
            }
            DataType::Int32 => {
                Ok(Arc::new(Int32Array::from(vec![] as Vec<i32>)) as ArrayRef)
            }
            DataType::Int16 => {
                Ok(Arc::new(Int16Array::from(vec![] as Vec<i16>)) as ArrayRef)
            }
            DataType::Int8 => {
                Ok(Arc::new(Int8Array::from(vec![] as Vec<i8>)) as ArrayRef)
            }
            DataType::UInt64 => {
                Ok(Arc::new(UInt64Array::from(vec![] as Vec<u64>)) as ArrayRef)
            }
            DataType::UInt32 => {
                Ok(Arc::new(UInt32Array::from(vec![] as Vec<u32>)) as ArrayRef)
            }
            DataType::UInt16 => {
                Ok(Arc::new(UInt16Array::from(vec![] as Vec<u16>)) as ArrayRef)
            }
            DataType::UInt8 => {
                Ok(Arc::new(UInt8Array::from(vec![] as Vec<u8>)) as ArrayRef)
            }
            DataType::Utf8 => {
                Ok(Arc::new(StringArray::from(vec![] as Vec<&str>)) as ArrayRef)
            }
            DataType::LargeUtf8 => {
                Ok(Arc::new(LargeStringArray::from(vec![] as Vec<&str>)) as ArrayRef)
            }
            DataType::Boolean => {
                Ok(Arc::new(BooleanArray::from(vec![] as Vec<bool>)) as ArrayRef)
            }
            _ => Err(DataFusionError::NotImplemented(format!(
                "Cannot convert datatype {:?} to array",
                f.data_type()
            ))),
        })
        .collect::<Result<_>>()
        .map_err(DataFusionError::into_arrow_external_error)?;
    RecordBatch::try_new(Arc::new(schema.to_owned()), columns)
}
<commit_msg>ARROW-11201: [Rust][DataFusion] create_batch_empty - support more types<commit_after>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

//! Defines common code used in execution plans

use std::fs;
use std::fs::metadata;
use std::sync::Arc;
use std::task::{Context, Poll};

use super::{RecordBatchStream, SendableRecordBatchStream};
use crate::error::{DataFusionError, Result};

use array::{
    ArrayData, BooleanArray, Date32Array, DecimalArray, Float32Array, Float64Array,
    Int16Array, Int32Array, Int64Array, Int8Array, LargeStringArray, StringArray,
    Time32MillisecondArray, Time32SecondArray, UInt16Array, UInt32Array, UInt64Array,
    UInt8Array,
};
use arrow::error::Result as ArrowResult;
use arrow::record_batch::RecordBatch;
use arrow::{
    array::{self, ArrayRef},
    datatypes::Schema,
};
use arrow::{
    array::{
        Date64Array, Time64MicrosecondArray, Time64NanosecondArray,
        TimestampMicrosecondArray, TimestampMillisecondArray, TimestampNanosecondArray,
        TimestampSecondArray,
    },
    buffer::Buffer,
    datatypes::{DataType, SchemaRef, TimeUnit},
};
use futures::{Stream, TryStreamExt};

/// Stream of record batches
pub struct SizedRecordBatchStream {
    schema: SchemaRef,
    batches: Vec<Arc<RecordBatch>>,
    index: usize,
}

impl SizedRecordBatchStream {
    /// Create a new RecordBatchIterator
    pub fn new(schema: SchemaRef, batches: Vec<Arc<RecordBatch>>) -> Self {
        SizedRecordBatchStream {
            schema,
            index: 0,
            batches,
        }
    }
}

impl Stream for SizedRecordBatchStream {
    type Item = ArrowResult<RecordBatch>;

    fn poll_next(
        mut self: std::pin::Pin<&mut Self>,
        _: &mut Context<'_>,
    ) -> Poll<Option<Self::Item>> {
        Poll::Ready(if self.index < self.batches.len() {
            self.index += 1;
            Some(Ok(self.batches[self.index - 1].as_ref().clone()))
        } else {
            None
        })
    }
}

impl RecordBatchStream for SizedRecordBatchStream {
    fn schema(&self) -> SchemaRef {
        self.schema.clone()
    }
}

/// Create a vector of record batches from a stream
pub async fn collect(stream: SendableRecordBatchStream) -> Result<Vec<RecordBatch>> {
    stream
        .try_collect::<Vec<_>>()
        .await
        .map_err(DataFusionError::from)
}

/// Recursively build a list of files in a directory with a given extension
pub fn build_file_list(dir: &str, filenames: &mut Vec<String>, ext: &str) -> Result<()> {
    let metadata = metadata(dir)?;
    if metadata.is_file() {
        if dir.ends_with(ext) {
            filenames.push(dir.to_string());
        }
    } else {
        for entry in fs::read_dir(dir)? {
            let entry = entry?;
            let path = entry.path();
            if let Some(path_name) = path.to_str() {
                if path.is_dir() {
                    build_file_list(path_name, filenames, ext)?;
                } else if path_name.ends_with(ext) {
                    filenames.push(path_name.to_string());
                }
            } else {
                return Err(DataFusionError::Plan("Invalid path".to_string()));
            }
        }
    }
    Ok(())
}

/// creates an empty record batch.
pub fn create_batch_empty(schema: &Schema) -> ArrowResult<RecordBatch> {
    let columns = schema
        .fields()
        .iter()
        .map(|f| match f.data_type() {
            DataType::Float32 => {
                Ok(Arc::new(Float32Array::from(vec![] as Vec<f32>)) as ArrayRef)
            }
            DataType::Float64 => {
                Ok(Arc::new(Float64Array::from(vec![] as Vec<f64>)) as ArrayRef)
            }
            DataType::Int64 => {
                Ok(Arc::new(Int64Array::from(vec![] as Vec<i64>)) as ArrayRef)
            }
            DataType::Int32 => {
                Ok(Arc::new(Int32Array::from(vec![] as Vec<i32>)) as ArrayRef)
            }
            DataType::Int16 => {
                Ok(Arc::new(Int16Array::from(vec![] as Vec<i16>)) as ArrayRef)
            }
            DataType::Int8 => {
                Ok(Arc::new(Int8Array::from(vec![] as Vec<i8>)) as ArrayRef)
            }
            DataType::UInt64 => {
                Ok(Arc::new(UInt64Array::from(vec![] as Vec<u64>)) as ArrayRef)
            }
            DataType::UInt32 => {
                Ok(Arc::new(UInt32Array::from(vec![] as Vec<u32>)) as ArrayRef)
            }
            DataType::UInt16 => {
                Ok(Arc::new(UInt16Array::from(vec![] as Vec<u16>)) as ArrayRef)
            }
            DataType::UInt8 => {
                Ok(Arc::new(UInt8Array::from(vec![] as Vec<u8>)) as ArrayRef)
            }
            DataType::Utf8 => {
                Ok(Arc::new(StringArray::from(vec![] as Vec<&str>)) as ArrayRef)
            }
            DataType::LargeUtf8 => {
                Ok(Arc::new(LargeStringArray::from(vec![] as Vec<&str>)) as ArrayRef)
            }
            DataType::Boolean => {
                Ok(Arc::new(BooleanArray::from(vec![] as Vec<bool>)) as ArrayRef)
            }
            DataType::Decimal(scale, precision) => {
                let array_data =
                    ArrayData::builder(DataType::Decimal(*scale, *precision))
                        .len(0)
                        .add_buffer(Buffer::from(&[]))
                        .build();

                Ok(Arc::new(DecimalArray::from(array_data)) as ArrayRef)
            }
            DataType::Timestamp(TimeUnit::Nanosecond, tz) => Ok(Arc::new(
                TimestampNanosecondArray::from_vec(vec![] as Vec<i64>, tz.clone()),
            )
                as ArrayRef),
            DataType::Timestamp(TimeUnit::Microsecond, tz) => Ok(Arc::new(
                TimestampMicrosecondArray::from_vec(vec![] as Vec<i64>, tz.clone()),
            )
                as ArrayRef),
            DataType::Timestamp(TimeUnit::Millisecond, tz) => Ok(Arc::new(
                TimestampMillisecondArray::from_vec(vec![] as Vec<i64>, tz.clone()),
            )
                as ArrayRef),
            DataType::Timestamp(TimeUnit::Second, tz) => Ok(Arc::new(
                TimestampSecondArray::from_vec(vec![] as Vec<i64>, tz.clone()),
            ) as ArrayRef),
            DataType::Date32(_) => {
                Ok(Arc::new(Date32Array::from(vec![] as Vec<i32>)) as ArrayRef)
            }
            DataType::Date64(_) => {
                Ok(Arc::new(Date64Array::from(vec![] as Vec<i64>)) as ArrayRef)
            }
            DataType::Time32(unit) => match unit {
                TimeUnit::Second => {
                    Ok(Arc::new(Time32SecondArray::from(vec![] as Vec<i32>)) as ArrayRef)
                }
                TimeUnit::Millisecond => {
                    Ok(Arc::new(Time32MillisecondArray::from(vec![] as Vec<i32>))
                        as ArrayRef)
                }
                TimeUnit::Microsecond | TimeUnit::Nanosecond => {
                    Err(DataFusionError::NotImplemented(format!(
                        "Cannot convert datatype {:?} to array",
                        f.data_type()
                    )))
                }
            },
            DataType::Time64(unit) => match unit {
                TimeUnit::Second | TimeUnit::Millisecond => {
                    Err(DataFusionError::NotImplemented(format!(
                        "Cannot convert datatype {:?} to array",
                        f.data_type()
                    )))
                }
                TimeUnit::Microsecond => {
                    Ok(Arc::new(Time64MicrosecondArray::from(vec![] as Vec<i64>))
                        as ArrayRef)
                }
                TimeUnit::Nanosecond => {
                    Ok(Arc::new(Time64NanosecondArray::from(vec![] as Vec<i64>))
                        as ArrayRef)
                }
            },
            _ => Err(DataFusionError::NotImplemented(format!(
                "Cannot convert datatype {:?} to array",
                f.data_type()
            ))),
        })
        .collect::<Result<_>>()
        .map_err(DataFusionError::into_arrow_external_error)?;

    RecordBatch::try_new(Arc::new(schema.to_owned()), columns)
}

#[cfg(test)]
mod tests {
    use super::*;
    use arrow::datatypes::Field;

    #[test]
    fn test_create_batch_empty() {
        let schema = Schema::new(vec![
            Field::new("c1", DataType::Utf8, false),
            Field::new("c2", DataType::UInt32, false),
            Field::new("c3", DataType::Int8, false),
            Field::new("c4", DataType::Int16, false),
            Field::new("c5", DataType::Int32, false),
            Field::new("c6", DataType::Int64, false),
            Field::new("c7", DataType::UInt8, false),
            Field::new("c8", DataType::UInt16, false),
            Field::new("c9", DataType::UInt32, false),
            Field::new("c10", DataType::UInt64, false),
            Field::new("c11", DataType::Float32, false),
            Field::new("c12", DataType::Float64, false),
            Field::new("c13", DataType::Utf8, false),
            Field::new("c14", DataType::Decimal(10, 10), false),
            Field::new("c15", DataType::Timestamp(TimeUnit::Second, None), false),
            Field::new(
                "c16",
                DataType::Timestamp(TimeUnit::Microsecond, None),
                false,
            ),
            Field::new(
                "c17",
                DataType::Timestamp(TimeUnit::Millisecond, None),
                false,
            ),
            Field::new(
                "c18",
                DataType::Timestamp(TimeUnit::Nanosecond, None),
                false,
            ),
            Field::new("c19", DataType::Boolean, false),
        ]);

        let batch = create_batch_empty(&schema).unwrap();
        assert_eq!(batch.columns().len(), 19);
    }
}
<|endoftext|>


<commit_before>use task_maker_format::ioi;
use turingarena::content::*;
use turingarena::evaluation::record::*;
use turingarena::feedback::{table::*, *};
use turingarena::problem::material::*;
use turingarena::score::*;
use turingarena::submission::form::*;

fn subtasks_of(task: &ioi::Task) -> Vec<&ioi::SubtaskInfo> {
    let mut subtasks: Vec<_> = task.subtasks.values().collect();
    subtasks.sort_by(|a, b| a.id.cmp(&b.id));
    subtasks
}

fn testcases_of(subtask: &ioi::SubtaskInfo) -> Vec<&ioi::TestcaseInfo> {
    let mut testcases: Vec<_> = subtask.testcases.values().collect();
    testcases.sort_by(|a, b| a.id.cmp(&b.id));
    testcases
}

fn submission_form() -> Form {
    Form {
        fields: vec![Field {
            id: FieldId("solution".into()),
            title: vec![TextVariant {
                attributes: vec![],
                value: "Solution".into(),
            }],
            types: vec![FileType {
                id: FileTypeId("cpp".into()),
                title: vec![TextVariant {
                    attributes: vec![],
                    value: "C++".into(),
                }],
                extensions: vec![
                    FileTypeExtension(".cpp".into()),
                    FileTypeExtension(".cc".into()),
                ],
                primary_extension: FileTypeExtension(".cpp".into()),
            }],
        }],
    }
}

fn scored_item_of(subtask: &ioi::SubtaskInfo) -> ScoredItem {
    ScoredItem {
        title: vec![TextVariant {
            attributes: vec![],
            value: format!("Subtask {}", subtask.id),
        }],
        range: Range {
            // TODO: assuming IOI-like tasks have integer scores
            precision: 0,
            max: Score(subtask.max_score),
        },
    }
}

fn cols() -> Vec<Col> {
    vec![
        Col {
            title: vec![TextVariant {
                attributes: vec![],
                value: format!("Case"),
            }],
            content: ColContent::RowNumber,
        },
        Col {
            title: vec![TextVariant {
                attributes: vec![],
                value: format!("Score"),
            }],
            content: ColContent::Score {
                range: Range {
                    // FIXME: assuming per-test-case score has fixed precision
                    precision: 2,
                    max: Score(1.),
                },
            },
        },
    ]
}

fn caption() -> Text {
    vec![TextVariant {
        attributes: vec![],
        value: format!("Test case results"),
    }]
}

fn row_group_of(subtask: &ioi::SubtaskInfo) -> RowGroup {
    RowGroup {
        title: vec![TextVariant {
            attributes: vec![],
            value: format!("Subtask {}", subtask.id),
        }],
        rows: testcases_of(subtask).into_iter().map(row_of).collect(),
    }
}

fn row_of(testcase: &ioi::TestcaseInfo) -> Row {
    Row {
        content: RowContent::Data,
        cells: vec![
            Cell {
                content: CellContent::RowNumber(testcase.id.into()),
            },
            Cell {
                content: CellContent::Score {
                    range: Range {
                        precision: 2,
                        max: Score(1.),
                    },
                    r#ref: Key(format!("testcase.{}.score", testcase.id)),
                },
            },
        ],
    }
}

pub fn gen_material(task: &ioi::Task) -> Material {
    Material {
        title: vec![TextVariant {
            attributes: vec![],
            value: task.name.clone().into(),
        }],
        statement: vec![],   // TODO
        attachments: vec![], // TODO
        submission_form: submission_form(),
        scored_items: { subtasks_of(task).into_iter().map(scored_item_of).collect() },
        feedback: vec![Section::Table {
            caption: caption(),
            cols: cols(),
            row_groups: subtasks_of(task).into_iter().map(row_group_of).collect(),
        }],
    }
}
<commit_msg>turingarena-task-maker: get statement<commit_after>use task_maker_format::ioi;
use turingarena::content::*;
use turingarena::evaluation::record::*;
use turingarena::feedback::{table::*, *};
use turingarena::problem::material::*;
use turingarena::score::*;
use turingarena::submission::form::*;

fn subtasks_of(task: &ioi::Task) -> Vec<&ioi::SubtaskInfo> {
    let mut subtasks: Vec<_> = task.subtasks.values().collect();
    subtasks.sort_by(|a, b| a.id.cmp(&b.id));
    subtasks
}

fn testcases_of(subtask: &ioi::SubtaskInfo) -> Vec<&ioi::TestcaseInfo> {
    let mut testcases: Vec<_> = subtask.testcases.values().collect();
    testcases.sort_by(|a, b| a.id.cmp(&b.id));
    testcases
}

fn submission_form() -> Form {
    Form {
        fields: vec![Field {
            id: FieldId("solution".into()),
            title: vec![TextVariant {
                attributes: vec![],
                value: "Solution".into(),
            }],
            types: vec![FileType {
                id: FileTypeId("cpp".into()),
                title: vec![TextVariant {
                    attributes: vec![],
                    value: "C++".into(),
                }],
                extensions: vec![
                    FileTypeExtension(".cpp".into()),
                    FileTypeExtension(".cc".into()),
                ],
                primary_extension: FileTypeExtension(".cpp".into()),
            }],
        }],
    }
}

fn scored_item_of(subtask: &ioi::SubtaskInfo) -> ScoredItem {
    ScoredItem {
        title: vec![TextVariant {
            attributes: vec![],
            value: format!("Subtask {}", subtask.id),
        }],
        range: Range {
            // TODO: assuming IOI-like tasks have integer scores
            precision: 0,
            max: Score(subtask.max_score),
        },
    }
}

fn cols() -> Vec<Col> {
    vec![
        Col {
            title: vec![TextVariant {
                attributes: vec![],
                value: format!("Case"),
            }],
            content: ColContent::RowNumber,
        },
        Col {
            title: vec![TextVariant {
                attributes: vec![],
                value: format!("Score"),
            }],
            content: ColContent::Score {
                range: Range {
                    // FIXME: assuming per-test-case score has fixed precision
                    precision: 2,
                    max: Score(1.),
                },
            },
        },
    ]
}

fn caption() -> Text {
    vec![TextVariant {
        attributes: vec![],
        value: format!("Test case results"),
    }]
}

fn row_group_of(subtask: &ioi::SubtaskInfo) -> RowGroup {
    RowGroup {
        title: vec![TextVariant {
            attributes: vec![],
            value: format!("Subtask {}", subtask.id),
        }],
        rows: testcases_of(subtask).into_iter().map(row_of).collect(),
    }
}

fn row_of(testcase: &ioi::TestcaseInfo) -> Row {
    Row {
        content: RowContent::Data,
        cells: vec![
            Cell {
                content: CellContent::RowNumber(testcase.id.into()),
            },
            Cell {
                content: CellContent::Score {
                    range: Range {
                        precision: 2,
                        max: Score(1.),
                    },
                    r#ref: Key(format!("testcase.{}.score", testcase.id)),
                },
            },
        ],
    }
}

fn booklet_of(task: &ioi::Task) -> FileVariant {
    let file_path = &task.path.join("testo.pdf");

    FileVariant {
        attributes: vec![VariantAttribute {
            key: "language".to_owned(),
            value: "it-IT".to_owned(), //TODO: get language from booklet
        }],
        name: Some(FileName("testo.pdf".to_owned())), //TODO: get filename from booklet
        r#type: Some(MediaType("application/pdf".to_owned())),
        content: std::fs::read(&file_path.to_string_lossy().as_ref()).unwrap(),
    }
}

pub fn gen_material(task: &ioi::Task) -> Material {
    Material {
        title: vec![TextVariant {
            attributes: vec![],
            value: task.name.clone().into(),
        }],
        statement: vec![booklet_of(task)],
        attachments: vec![], // TODO
        submission_form: submission_form(),
        scored_items: { subtasks_of(task).into_iter().map(scored_item_of).collect() },
        feedback: vec![Section::Table {
            caption: caption(),
            cols: cols(),
            row_groups: subtasks_of(task).into_iter().map(row_group_of).collect(),
        }],
    }
}
<|endoftext|>


<commit_before>use parking_lot::RwLock;
use std::ops::Index;
use std::sync::Arc;

use dora_parser::ast;
use dora_parser::interner::Name;
use dora_parser::lexer::position::Position;

use crate::ty::SourceType;
use crate::vm::{
    accessible_from, namespace_path, FctId, FileId, NamespaceId, TypeParam, TypeParamId, VM,
};

#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct TraitId(u32);

impl From<u32> for TraitId {
    fn from(data: u32) -> TraitId {
        TraitId(data)
    }
}

#[derive(Debug)]
pub struct TraitData {
    pub id: TraitId,
    pub file_id: FileId,
    pub namespace_id: NamespaceId,
    pub is_pub: bool,
    pub ast: Arc<ast::Trait>,
    pub pos: Position,
    pub name: Name,
    pub type_params: Vec<TypeParam>,
    pub methods: Vec<FctId>,
}

impl TraitData {
    pub fn name(&self, vm: &VM) -> String {
        namespace_path(vm, self.namespace_id, self.name)
    }

    pub fn find_method(&self, vm: &VM, name: Name, is_static: bool) -> Option<FctId> {
        for &method in &self.methods {
            let method = vm.fcts.idx(method);
            let method = method.read();

            if method.name == name && method.is_static == is_static {
                return Some(method.id);
            }
        }

        None
    }

    pub fn find_method_with_replace(
        &self,
        vm: &VM,
        is_static: bool,
        name: Name,
        replace: Option<SourceType>,
        args: &[SourceType],
    ) -> Option<FctId> {
        for &method in &self.methods {
            let method = vm.fcts.idx(method);
            let method = method.read();

            if method.name == name
                && method.is_static == is_static
                && params_match(replace.clone(), method.params_without_self(), args)
            {
                return Some(method.id);
            }
        }

        None
    }

    pub fn type_param(&self, id: TypeParamId) -> &TypeParam {
        &self.type_params[id.to_usize()]
    }
}

fn params_match(
    replace: Option<SourceType>,
    trait_args: &[SourceType],
    args: &[SourceType],
) -> bool {
    if trait_args.len() != args.len() {
        return false;
    }

    for (ind, ty) in trait_args.iter().enumerate() {
        let ty = ty.clone();
        let other = args[ind].clone();

        let found = if ty.is_self() {
            replace.is_none() || replace.clone().unwrap() == other
        } else {
            ty == other
        };

        if !found {
            return false;
        }
    }

    true
}

impl Index<TraitId> for Vec<RwLock<TraitData>> {
    type Output = RwLock<TraitData>;

    fn index(&self, index: TraitId) -> &RwLock<TraitData> {
        &self[index.0 as usize]
    }
}

pub fn trait_accessible_from(vm: &VM, trait_id: TraitId, namespace_id: NamespaceId) -> bool {
    let xtrait = vm.traits[trait_id].read();

    accessible_from(vm, xtrait.namespace_id, xtrait.is_pub, namespace_id)
}
<commit_msg>add TraitType<commit_after>use parking_lot::RwLock;
use std::ops::Index;
use std::sync::Arc;

use dora_parser::ast;
use dora_parser::interner::Name;
use dora_parser::lexer::position::Position;

use crate::ty::{SourceType, SourceTypeArray};
use crate::vm::{
    accessible_from, namespace_path, FctId, FileId, NamespaceId, TypeParam, TypeParamId, VM,
};

#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct TraitId(u32);

impl From<u32> for TraitId {
    fn from(data: u32) -> TraitId {
        TraitId(data)
    }
}

#[derive(Debug)]
pub struct TraitData {
    pub id: TraitId,
    pub file_id: FileId,
    pub namespace_id: NamespaceId,
    pub is_pub: bool,
    pub ast: Arc<ast::Trait>,
    pub pos: Position,
    pub name: Name,
    pub type_params: Vec<TypeParam>,
    pub methods: Vec<FctId>,
}

impl TraitData {
    pub fn name(&self, vm: &VM) -> String {
        namespace_path(vm, self.namespace_id, self.name)
    }

    pub fn find_method(&self, vm: &VM, name: Name, is_static: bool) -> Option<FctId> {
        for &method in &self.methods {
            let method = vm.fcts.idx(method);
            let method = method.read();

            if method.name == name && method.is_static == is_static {
                return Some(method.id);
            }
        }

        None
    }

    pub fn find_method_with_replace(
        &self,
        vm: &VM,
        is_static: bool,
        name: Name,
        replace: Option<SourceType>,
        args: &[SourceType],
    ) -> Option<FctId> {
        for &method in &self.methods {
            let method = vm.fcts.idx(method);
            let method = method.read();

            if method.name == name
                && method.is_static == is_static
                && params_match(replace.clone(), method.params_without_self(), args)
            {
                return Some(method.id);
            }
        }

        None
    }

    pub fn type_param(&self, id: TypeParamId) -> &TypeParam {
        &self.type_params[id.to_usize()]
    }
}

struct TraitType {
    trait_id: TraitId,
    type_params: SourceTypeArray,
}

fn params_match(
    replace: Option<SourceType>,
    trait_args: &[SourceType],
    args: &[SourceType],
) -> bool {
    if trait_args.len() != args.len() {
        return false;
    }

    for (ind, ty) in trait_args.iter().enumerate() {
        let ty = ty.clone();
        let other = args[ind].clone();

        let found = if ty.is_self() {
            replace.is_none() || replace.clone().unwrap() == other
        } else {
            ty == other
        };

        if !found {
            return false;
        }
    }

    true
}

impl Index<TraitId> for Vec<RwLock<TraitData>> {
    type Output = RwLock<TraitData>;

    fn index(&self, index: TraitId) -> &RwLock<TraitData> {
        &self[index.0 as usize]
    }
}

pub fn trait_accessible_from(vm: &VM, trait_id: TraitId, namespace_id: NamespaceId) -> bool {
    let xtrait = vm.traits[trait_id].read();

    accessible_from(vm, xtrait.namespace_id, xtrait.is_pub, namespace_id)
}
<|endoftext|>


<commit_before>pub mod space;
pub mod seq;
pub mod set;
pub mod choice;
pub mod int;
pub mod spec;

use nom::{is_alphanumeric, alpha, digit};
use parse::space::skip_other;
use parse::seq::asn1_seq;
use parse::set::asn1_set;
use parse::choice::asn1_choice;
use parse::int::asn1_integer;
use data::{Asn1Type, Asn1Class, Asn1Tag, Asn1Def, Asn1Field, Asn1Optional};

named!(pub asn1_type_name <String>, do_parse!(
  s: take_while!(is_alphanumeric) >>
  (String::from_utf8(Vec::from(s)).unwrap())
));

named!(pub asn1_class_tag <Asn1Tag>, do_parse!(
  class: opt!(alpha) >>
  opt!(skip_other) >>
  tag_num: digit >>
  ( {
      let class = class.and_then(|i|
        String::from_utf8(Vec::from(i)).ok()
      );
      Asn1Class::parse(class).expect("Couldn't parse tag class")
    },
    String::from_utf8(Vec::from(tag_num)).unwrap().parse().expect("Couldn't parse tag number")
  )
));

named!(pub asn1_tag <Asn1Tag>, do_parse!(
  tag: delimited!(
    tag!("["),
    asn1_class_tag,
    tuple!(opt!(skip_other), tag!("]"))
  ) >>
  (tag)
));

named!(pub asn1_type_def <Asn1Def>, do_parse!(
  name: asn1_type_name >>
  opt!(skip_other) >>
  tag!("::=") >>
  opt!(skip_other) >>
  tag: opt!(asn1_tag) >>
  opt!(skip_other) >>
  asn1_type: asn1_type >>
  (Asn1Def {
    name: name,
    tag: tag,
    assign: asn1_type,
  })
));

named!(pub asn1_type <Asn1Type>, alt!(
  do_parse!(s: asn1_seq >> (Asn1Type::Seq(s))) |
  do_parse!(s: asn1_set >> (Asn1Type::Set(s))) |
  do_parse!(c: asn1_choice >> (Asn1Type::Choice(c))) |
  do_parse!(i: asn1_integer >> (Asn1Type::Integer(i))) |
  do_parse!(t: asn1_assignment >> (Asn1Type::Type(t)))
));

named!(pub asn1_assignment <String>, call!(asn1_type_name));

named!(pub asn1_field <Asn1Field>, do_parse!(
  name: asn1_type_name >>
  opt!(skip_other) >>
  tag: opt!(asn1_tag) >>
  opt!(skip_other) >>
  asn1_type: asn1_type >>
  opt!(skip_other) >>
  optional: opt!(alt!(asn1_field_optional | asn1_field_default)) >>
  (Asn1Field {
    name: name,
    tag: tag,
    asn1_type: asn1_type,
    optional: optional,
  })
));

named!(pub asn1_field_optional <Asn1Optional>, do_parse!(
  tag!("OPTIONAL") >>
  (Asn1Optional::Optional)
));

named!(pub asn1_field_default <Asn1Optional>, do_parse!(
  tag!("DEFAULT") >>
  opt!(skip_other) >>
  default: take_while!(is_alphanumeric) >>
  (Asn1Optional::Default(
    String::from_utf8(Vec::from(default)).unwrap()
  ))
));

#[test]
fn test_asn1_tag() {
  let tag: Asn1Tag = (Asn1Class::ContextSpecific, 32);
  assert_eq!(asn1_tag("[32]".as_bytes()).unwrap().1, tag);
  assert_eq!(asn1_tag("[ 32 ]".as_bytes()).unwrap().1, tag);
  assert_eq!(
    asn1_tag("[APPLICATION 12]".as_bytes()).unwrap().1,
    (Asn1Class::Application, 12)
  );
  assert_eq!(
    asn1_tag("[PRIVATE 24]".as_bytes()).unwrap().1,
    (Asn1Class::Private, 24)
  );
}

#[test]
fn test_asn1_field() {
  let field1 = ::Asn1Field {
    name: "foo".into(),
    tag: None,
    asn1_type: ::Asn1Type::Type("Bar".into()),
    optional: None,
  };
  let field2 = ::Asn1Field {
    name: "asdf".into(),
    tag: Some((Asn1Class::Application, 9)),
    asn1_type: ::Asn1Type::Integer(::Asn1Integer),
    optional: Some(Asn1Optional::Optional),
  };
  let field3 = ::Asn1Field {
    name: "sample".into(),
    tag: None,
    asn1_type: ::Asn1Type::Integer(::Asn1Integer),
    optional: Some(Asn1Optional::Default("TRUE".into())),
  };
  assert_eq!(
    field1,
    asn1_field("foo Bar,".as_bytes()).unwrap().1
  );
  assert_eq!(
    field2,
    asn1_field("asdf [APPLICATION 9] INTEGER OPTIONAL,".as_bytes()).unwrap().1
  );
  assert_eq!(
    field1,
    asn1_field("foo--test\n Bar,".as_bytes()).unwrap().1
  );
  assert_eq!(
    field3,
    asn1_field("sample INTEGER DEFAULT TRUE,".as_bytes()).unwrap().1
  );
}
<commit_msg>Add basic recognition for OCTET STRING<commit_after>pub mod space;
pub mod seq;
pub mod set;
pub mod choice;
pub mod int;
pub mod spec;

use nom::{is_alphanumeric, alpha, digit};
use parse::space::skip_other;
use parse::seq::asn1_seq;
use parse::set::asn1_set;
use parse::choice::asn1_choice;
use parse::int::asn1_integer;
use data::{Asn1Type, Asn1Class, Asn1Tag, Asn1Def, Asn1Field, Asn1Optional};

named!(pub asn1_class_tag <Asn1Tag>, do_parse!(
  class: opt!(alpha) >>
  opt!(skip_other) >>
  tag_num: digit >>
  ( {
      let class = class.and_then(|i|
        String::from_utf8(Vec::from(i)).ok()
      );
      Asn1Class::parse(class).expect("Couldn't parse tag class")
    },
    String::from_utf8(Vec::from(tag_num)).unwrap().parse().expect("Couldn't parse tag number")
  )
));

named!(pub asn1_tag <Asn1Tag>, do_parse!(
  tag: delimited!(
    tag!("["),
    asn1_class_tag,
    tuple!(opt!(skip_other), tag!("]"))
  ) >>
  (tag)
));

named!(pub asn1_type_def <Asn1Def>, do_parse!(
  name: asn1_type_name >>
  opt!(skip_other) >>
  tag!("::=") >>
  opt!(skip_other) >>
  tag: opt!(asn1_tag) >>
  opt!(skip_other) >>
  asn1_type: asn1_type >>
  (Asn1Def {
    name: name,
    tag: tag,
    assign: asn1_type,
  })
));

named!(pub asn1_type <Asn1Type>, alt!(
  do_parse!(s: asn1_seq >> (Asn1Type::Seq(s))) |
  do_parse!(s: asn1_set >> (Asn1Type::Set(s))) |
  do_parse!(c: asn1_choice >> (Asn1Type::Choice(c))) |
  do_parse!(i: asn1_integer >> (Asn1Type::Integer(i))) |
  do_parse!(t: asn1_assignment >> (Asn1Type::Type(t)))
));

named!(pub asn1_type_name <String>, do_parse!(
  s: alt!(
    tag!("BIT STRING") |
    tag!("OCTET STRING") |
    tag!("OBJECT IDENTIFIER") |
    tag!("INSTANCE OF") |
    tag!("EMBEDDED PDV") |
    tag!("CHARACTER STRING") |
    take_while!(is_alphanumeric)
  ) >>
  (String::from_utf8(Vec::from(s)).unwrap())
));

named!(pub asn1_assignment <String>, call!(asn1_type_name));

named!(pub asn1_field <Asn1Field>, do_parse!(
  name: asn1_type_name >>
  opt!(skip_other) >>
  tag: opt!(asn1_tag) >>
  opt!(skip_other) >>
  asn1_type: asn1_type >>
  opt!(skip_other) >>
  optional: opt!(alt!(asn1_field_optional | asn1_field_default)) >>
  (Asn1Field {
    name: name,
    tag: tag,
    asn1_type: asn1_type,
    optional: optional,
  })
));

named!(pub asn1_field_optional <Asn1Optional>, do_parse!(
  tag!("OPTIONAL") >>
  (Asn1Optional::Optional)
));

named!(pub asn1_field_default <Asn1Optional>, do_parse!(
  tag!("DEFAULT") >>
  opt!(skip_other) >>
  default: take_while!(is_alphanumeric) >>
  (Asn1Optional::Default(
    String::from_utf8(Vec::from(default)).unwrap()
  ))
));

#[test]
fn test_asn1_type() {
  assert_eq!(asn1_type_name("Foo Bar".as_bytes()).unwrap().1, "Foo");
  assert_eq!(asn1_type_name("OCTET STRING".as_bytes()).unwrap().1, "OCTET STRING");
}

#[test]
fn test_asn1_tag() {
  let tag: Asn1Tag = (Asn1Class::ContextSpecific, 32);
  assert_eq!(asn1_tag("[32]".as_bytes()).unwrap().1, tag);
  assert_eq!(asn1_tag("[ 32 ]".as_bytes()).unwrap().1, tag);
  assert_eq!(
    asn1_tag("[APPLICATION 12]".as_bytes()).unwrap().1,
    (Asn1Class::Application, 12)
  );
  assert_eq!(
    asn1_tag("[PRIVATE 24]".as_bytes()).unwrap().1,
    (Asn1Class::Private, 24)
  );
}

#[test]
fn test_asn1_field() {
  let field1 = ::Asn1Field {
    name: "foo".into(),
    tag: None,
    asn1_type: ::Asn1Type::Type("Bar".into()),
    optional: None,
  };
  let field2 = ::Asn1Field {
    name: "asdf".into(),
    tag: Some((Asn1Class::Application, 9)),
    asn1_type: ::Asn1Type::Integer(::Asn1Integer),
    optional: Some(Asn1Optional::Optional),
  };
  let field3 = ::Asn1Field {
    name: "sample".into(),
    tag: None,
    asn1_type: ::Asn1Type::Integer(::Asn1Integer),
    optional: Some(Asn1Optional::Default("TRUE".into())),
  };
  assert_eq!(
    field1,
    asn1_field("foo Bar,".as_bytes()).unwrap().1
  );
  assert_eq!(
    field2,
    asn1_field("asdf [APPLICATION 9] INTEGER OPTIONAL,".as_bytes()).unwrap().1
  );
  assert_eq!(
    field1,
    asn1_field("foo--test\n Bar,".as_bytes()).unwrap().1
  );
  assert_eq!(
    field3,
    asn1_field("sample INTEGER DEFAULT TRUE,".as_bytes()).unwrap().1
  );
}
<|endoftext|>


<commit_before>//! [β-reduction](https://en.wikipedia.org/wiki/Beta_normal_form) for lambda `Term`s

use term::*;
use term::Term::*;
use self::Order::*;

/// Set to `true` to see all the steps of β-reductions. The default is `false`.
pub const SHOW_REDUCTIONS: bool = false;

/// The [evaluation order](https://en.wikipedia.org/wiki/Lambda_calculus#Reduction_strategies) of
/// β-reductions. `Applicative` order will fail to fully reduce expressions containing functions
/// without a normal form, e.g. the Y combinator (they will expand forever). `CallByName`,
/// `HeadSpine` and `CallByValue` orders don't always normalize fully. The default is `Normal`.
#[derive(Debug, PartialEq)]
pub enum Order {
    /// leftmost outermost
    Normal,
    /// leftmost outermost, but not inside abstractions
    CallByName,
    /// leftmost outermost, but abstractions reduced only in head position
    HeadSpine,
    /// `HeadSpine` + `Normal`
    HybridNormal,
    /// leftmost innermost
    Applicative,
    /// leftmost innermost, but not inside abstractions
    CallByValue,
    /// `CallByValue` + `Applicative`
    HybridApplicative
}

/// Applies two `Term`s with substitution and variable update, consuming the first one in the
/// process.
///
/// # Example
/// ```
/// use lambda_calculus::reduction::apply;
/// use lambda_calculus::parser::parse;
///
/// let lhs    = parse(&"λλ42(λ13)").unwrap();
/// let rhs    = parse(&"λ51").unwrap();
/// let result = parse(&"λ3(λ61)(λ1(λ71))").unwrap();
///
/// assert_eq!(apply(lhs, &rhs), Ok(result));
/// ```
pub fn apply(mut lhs: Term, rhs: &Term) -> Result<Term, Error> {
    _apply(&mut lhs, rhs, 0);

    lhs.unabs()
}

fn _apply(lhs: &mut Term, rhs: &Term, depth: usize) {
    match *lhs {
        Var(i) => if i == depth {
            *lhs = rhs.clone(); // substitute a top-level variable from lhs with rhs
            update_free_variables(lhs, depth - 1, 0); // update indices of free variables from rhs
        } else if i > depth {
            *lhs = Var(i - 1) // decrement a free variable's index
        },
        Abs(_) => {
            _apply(lhs.unabs_ref_mut().unwrap(), rhs, depth + 1)
        },
        App(_, _) => {
            _apply(lhs.lhs_ref_mut().unwrap(), rhs, depth);
            _apply(lhs.rhs_ref_mut().unwrap(), rhs, depth)
        }
    }
}

fn update_free_variables(term: &mut Term, added_depth: usize, own_depth: usize) {
    match *term {
        Var(i) => if i > own_depth {
            *term = Var(i + added_depth)
        },
        Abs(_) => {
            update_free_variables(term.unabs_ref_mut().unwrap(), added_depth, own_depth + 1)
        },
        App(_, _) => {
            update_free_variables(term.lhs_ref_mut().unwrap(), added_depth, own_depth);
            update_free_variables(term.rhs_ref_mut().unwrap(), added_depth, own_depth)
        }
    }
}

impl Term {
    /// Applies `self` to another `Term` and performs substitution, consuming `self` in the process.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::parser::parse;
    ///
    /// let lhs    = parse(&"λλ42(λ13)").unwrap();
    /// let rhs    = parse(&"λ51").unwrap();
    /// let result = parse(&"λ3(λ61)(λ1(λ71))").unwrap();
    ///
    /// assert_eq!(lhs.apply(&rhs), Ok(result));
    /// ```
    pub fn apply(self, rhs: &Term) -> Result<Term, Error> {
        apply(self, rhs)
    }

    /// Reduces an `App`lication by substitution and variable update.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::term::{app, abs};
    /// use lambda_calculus::term::Term::Var;
    /// use lambda_calculus::arithmetic::zero;
    /// use lambda_calculus::combinators::i;
    ///
    /// assert_eq!(app(i(), zero()).eval(), Ok(zero()));
    /// ```
    pub fn eval(self) -> Result<Term, Error> {
        let (lhs, rhs) = try!(self.unapp());

        apply(lhs, &rhs)
    }

    /// Performs a single β-reduction on `self` with the specified evaluation `Order`.
    ///
    /// # Example
    ///
    /// ```
    /// use lambda_calculus::arithmetic::succ;
    /// use lambda_calculus::reduction::Order;
    ///
    /// let mut succ_one = succ().app(1.into());
    /// succ_one.beta_once(&Order::Normal);
    ///
    /// assert_eq!(succ_one, succ().apply(&1.into()).unwrap());
    /// ```
    pub fn beta_once(&mut self, order: &Order) {
        self.beta_once_indicative(order);
    }

    fn beta_once_indicative(&mut self, order: &Order) -> bool {
        match *order {
            Normal       => self._beta_once_normal(0),
            CallByName   => self._beta_once_call_by_name(),
            HeadSpine    => self._beta_once_head_spine(0, true),
            Applicative  => self._beta_once_applicative(0),
            CallByValue  => self._beta_once_call_by_value(),
            HybridNormal => {
                self._beta_once_head_spine(0, true);
                self._beta_once_normal(0)
            },
            HybridApplicative => self._beta_once_hybrid_applicative(0)
        }
    }

    fn eval_with_info(&mut self, depth: u32) {
        if SHOW_REDUCTIONS { print!("    {} reduces to ", show_precedence(self, 0, depth)) };
        let copy = self.clone();
        *self = copy.eval().unwrap();
        if SHOW_REDUCTIONS { println!("{}", show_precedence(self, 0, depth)) }
    }

    // the return value indicates if reduction was performed
    fn _beta_once_normal(&mut self, depth: u32) -> bool {
        match *self {
            Var(_) => false,
            Abs(_) => self.unabs_ref_mut().unwrap()._beta_once_normal(depth + 1),
            App(_, _) => {
                if self.lhs_ref().unwrap().unabs_ref().is_ok() {
                    self.eval_with_info(depth);
                    true
                } else {
                    self.lhs_ref_mut().unwrap()._beta_once_normal(depth) ||
                    self.rhs_ref_mut().unwrap()._beta_once_normal(depth)
                }
            }
        }
    }

    // the return value indicates if reduction was performed
    fn _beta_once_call_by_name(&mut self) -> bool {
        match *self {
            App(_, _) => {
                if self.lhs_ref().unwrap().unabs_ref().is_ok() {
                    self.eval_with_info(0);
                    true
                } else {
                    self.lhs_ref_mut().unwrap()._beta_once_call_by_name()
                }
            },
            _ => false
        }
    }

    // the return value indicates if reduction was performed
    fn _beta_once_head_spine(&mut self, depth: u32, is_head: bool) -> bool {
        match *self {
            Var(_) => false,
            Abs(_) => if is_head {
                self.unabs_ref_mut().unwrap()._beta_once_head_spine(depth + 1, is_head)
            } else {
                false
            },
            App(_, _) => {
                if self.lhs_ref().unwrap().unabs_ref().is_ok() {
                    self.eval_with_info(0);
                    true
                } else {
                    self.lhs_ref_mut().unwrap()._beta_once_head_spine(depth, is_head) ||
                    self.rhs_ref_mut().unwrap()._beta_once_head_spine(depth, false)
                }
            }
        }
    }

    // the return value indicates if reduction was performed
    fn _beta_once_applicative(&mut self, depth: u32) -> bool {
        match *self {
            Var(_) => false,
            Abs(_) => self.unabs_ref_mut().unwrap()._beta_once_applicative(depth + 1),
            App(_, _) => {
                if  self.lhs_ref().unwrap().unabs_ref().is_ok() &&
                   !self.rhs_ref().unwrap().is_beta_reducible(&Applicative)
                {
                    self.eval_with_info(depth);
                    true
                } else {
                    self.lhs_ref_mut().unwrap()._beta_once_applicative(depth) ||
                    self.rhs_ref_mut().unwrap()._beta_once_applicative(depth)
                }
            }
        }
    }

    // the return value indicates if reduction was performed
    fn _beta_once_call_by_value(&mut self) -> bool {
        match *self {
            App(_, _) => {
                if self.lhs_ref().unwrap().unabs_ref().is_ok() {
                    if self.rhs_ref_mut().unwrap().is_beta_reducible(&CallByValue) {
                        self.rhs_ref_mut().unwrap()._beta_once_call_by_value()
                    } else {
                        self.eval_with_info(0);
                        true
                    }
                } else {
                    self.rhs_ref_mut().unwrap()._beta_once_call_by_value()
                }
            },
            _ => false
        }
    }

    // the return value indicates if reduction was performed
    fn _beta_once_hybrid_applicative(&mut self, depth: u32) -> bool {
        match *self {
            Var(_) => false,
            Abs(_) => self.unabs_ref_mut().unwrap()._beta_once_hybrid_applicative(depth + 1),
            App(_, _) => {
                if self.lhs_ref().unwrap().unabs_ref().is_ok() {
                    if self.rhs_ref_mut().unwrap().is_beta_reducible(&CallByValue) {
                        self.rhs_ref_mut().unwrap()._beta_once_call_by_value()
                    } else {
                        self.eval_with_info(0);
                        true
                    }
                } else {
                    self.lhs_ref_mut().unwrap()._beta_once_hybrid_applicative(depth) ||
                    self.rhs_ref_mut().unwrap()._beta_once_hybrid_applicative(depth)
                }
            }
        }
    }

    /// Checks whether `self` is β-reducible under the specified evaluation `Order`.
    ///
    /// # Example
    ///
    /// ```
    /// use lambda_calculus::arithmetic::{succ, zero};
    /// use lambda_calculus::reduction::Order;
    ///
    /// let reducible     = succ().app(1.into());
    /// let not_reducible = zero();
    ///
    /// assert!(reducible.is_beta_reducible(&Order::Normal));
    /// assert!(!not_reducible.is_beta_reducible(&Order::Normal));
    /// ```
    pub fn is_beta_reducible(&self, order: &Order) -> bool {
        match *self {
            Var(_) => false,
            Abs(_) => match *order {
                Normal | Applicative => self.unabs_ref().unwrap().is_beta_reducible(order),
                _ => false
            },
            App(_, _) => {
                if self.lhs_ref().unwrap().unabs_ref().is_ok() {
                    true
                } else {
                    self.lhs_ref().unwrap().is_beta_reducible(order) ||
                    self.rhs_ref().unwrap().is_beta_reducible(order)
                }
            }
        }
    }

    /// Performs full β-reduction on `self` using the specified evaluation `Order`.
    ///
    /// # Example
    ///
    /// ```
    /// use lambda_calculus::arithmetic::pred;
    /// use lambda_calculus::reduction::Order;
    ///
    /// let mut pred_one = pred().app(1.into());
    /// pred_one.beta_full(&Order::Normal);
    ///
    /// assert_eq!(pred_one, 0.into());
    /// ```
    pub fn beta_full(&mut self, order: &Order) {
        loop {
            if SHOW_REDUCTIONS { println!("reducing {}", self) }
            if !self.beta_once_indicative(order) { break }
        }
        if SHOW_REDUCTIONS { println!("    doesn't reduce") }
    }
}

/// Performs full β-reduction on a `Term` using the specified evaluation `Order`, consuming its
/// argument in the process.
///
/// # Example
///
/// ```
/// use lambda_calculus::arithmetic::pred;
/// use lambda_calculus::reduction::{beta_full, Order};
///
/// let pred_one = pred().app(1.into());
///
/// assert_eq!(beta_full(pred_one, &Order::Normal), 0.into());
/// ```
pub fn beta_full(mut term: Term, order: &Order) -> Term {
    term.beta_full(order);
    term
}

/// Performs a single β-reduction on a `Term` using the specified evaluation `Order`, consuming its
/// argument in the process.
///
/// # Example
///
/// ```
/// use lambda_calculus::arithmetic::succ;
/// use lambda_calculus::reduction::{beta_once, Order};
///
/// let succ_one = succ().app(1.into());
///
/// assert_eq!(beta_once(succ_one, &Order::Normal), succ().apply(&1.into()).unwrap());
/// ```
pub fn beta_once(mut term: Term, order: &Order) -> Term {
    term.beta_once(order);
    term
}

#[cfg(test)]
mod test {
    use super::*;
    use parser::parse;
    use combinators::{i, y};

    #[test]
    fn normal_order() {
        let reduces_instantly = parse(&"(λλ1)((λλλ((32)1))(λλ2))").unwrap();
        assert_eq!(beta_full(reduces_instantly.clone(), &Normal),
                   beta_once(reduces_instantly, &Normal));

        let should_reduce = parse(&"(λ2)((λ111)(λ111))").unwrap();
        assert_eq!(beta_full(should_reduce, &Normal), Var(1))
    }

    #[test]
    fn call_by_name_order() {
        let mut expr = app(abs(app(i(), Var(1))), app(i(), i()));
        expr.beta_once(&CallByName);
        assert_eq!(expr, app(i(), app(i(), i())));
        expr.beta_once(&CallByName);
        assert_eq!(expr, app(i(), i()));
        expr.beta_once(&CallByName);
        assert_eq!(expr, i());
    }

    #[test]
    fn applicative_order() {
        let expr = parse(&"λ1(((λλλ1)1)((λλ21)1))").unwrap();
        assert_eq!(&format!("{}", beta_once(expr, &Applicative)), "λ1((λλ1)((λλ21)1))");

        let expands = parse(&"(λ2)((λ111)(λ111))").unwrap();
        assert_eq!(&format!("{}", beta_once(expands, &Applicative)), "(λ2)((λ111)(λ111)(λ111))")
    }

    #[test]
    fn call_by_value_order() {
        let mut expr = app(abs(app(i(), Var(1))), app(i(), i()));
        expr.beta_once(&CallByValue);
        assert_eq!(expr, app(abs(app(i(), Var(1))), i()));
        expr.beta_once(&CallByValue);
        assert_eq!(expr, app(i(), i()));
        expr.beta_once(&CallByValue);
        assert_eq!(expr, i());
    }

    #[test]
    fn reducibility() {
        assert!(y().is_beta_reducible(&Normal));
        assert!(y().is_beta_reducible(&Applicative));
        assert!(!y().is_beta_reducible(&CallByName));
        assert!(!y().is_beta_reducible(&CallByValue));
    }
}
<commit_msg>eval_with_info() now returns true<commit_after>//! [β-reduction](https://en.wikipedia.org/wiki/Beta_normal_form) for lambda `Term`s

use term::*;
use term::Term::*;
use self::Order::*;

/// Set to `true` to see all the steps of β-reductions. The default is `false`.
pub const SHOW_REDUCTIONS: bool = false;

/// The [evaluation order](https://en.wikipedia.org/wiki/Lambda_calculus#Reduction_strategies) of
/// β-reductions. `Applicative` order will fail to fully reduce expressions containing functions
/// without a normal form, e.g. the Y combinator (they will expand forever). `CallByName`,
/// `HeadSpine` and `CallByValue` orders don't always normalize fully. The default is `Normal`.
#[derive(Debug, PartialEq)]
pub enum Order {
    /// leftmost outermost
    Normal,
    /// leftmost outermost, but not inside abstractions
    CallByName,
    /// leftmost outermost, but abstractions reduced only in head position
    HeadSpine,
    /// `HeadSpine` + `Normal`
    HybridNormal,
    /// leftmost innermost
    Applicative,
    /// leftmost innermost, but not inside abstractions
    CallByValue,
    /// `CallByValue` + `Applicative`
    HybridApplicative
}

/// Applies two `Term`s with substitution and variable update, consuming the first one in the
/// process.
///
/// # Example
/// ```
/// use lambda_calculus::reduction::apply;
/// use lambda_calculus::parser::parse;
///
/// let lhs    = parse(&"λλ42(λ13)").unwrap();
/// let rhs    = parse(&"λ51").unwrap();
/// let result = parse(&"λ3(λ61)(λ1(λ71))").unwrap();
///
/// assert_eq!(apply(lhs, &rhs), Ok(result));
/// ```
pub fn apply(mut lhs: Term, rhs: &Term) -> Result<Term, Error> {
    _apply(&mut lhs, rhs, 0);

    lhs.unabs()
}

fn _apply(lhs: &mut Term, rhs: &Term, depth: usize) {
    match *lhs {
        Var(i) => if i == depth {
            *lhs = rhs.clone(); // substitute a top-level variable from lhs with rhs
            update_free_variables(lhs, depth - 1, 0); // update indices of free variables from rhs
        } else if i > depth {
            *lhs = Var(i - 1) // decrement a free variable's index
        },
        Abs(_) => {
            _apply(lhs.unabs_ref_mut().unwrap(), rhs, depth + 1)
        },
        App(_, _) => {
            _apply(lhs.lhs_ref_mut().unwrap(), rhs, depth);
            _apply(lhs.rhs_ref_mut().unwrap(), rhs, depth)
        }
    }
}

fn update_free_variables(term: &mut Term, added_depth: usize, own_depth: usize) {
    match *term {
        Var(i) => if i > own_depth {
            *term = Var(i + added_depth)
        },
        Abs(_) => {
            update_free_variables(term.unabs_ref_mut().unwrap(), added_depth, own_depth + 1)
        },
        App(_, _) => {
            update_free_variables(term.lhs_ref_mut().unwrap(), added_depth, own_depth);
            update_free_variables(term.rhs_ref_mut().unwrap(), added_depth, own_depth)
        }
    }
}

impl Term {
    /// Applies `self` to another `Term` and performs substitution, consuming `self` in the process.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::parser::parse;
    ///
    /// let lhs    = parse(&"λλ42(λ13)").unwrap();
    /// let rhs    = parse(&"λ51").unwrap();
    /// let result = parse(&"λ3(λ61)(λ1(λ71))").unwrap();
    ///
    /// assert_eq!(lhs.apply(&rhs), Ok(result));
    /// ```
    pub fn apply(self, rhs: &Term) -> Result<Term, Error> {
        apply(self, rhs)
    }

    /// Reduces an `App`lication by substitution and variable update.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::term::{app, abs};
    /// use lambda_calculus::term::Term::Var;
    /// use lambda_calculus::arithmetic::zero;
    /// use lambda_calculus::combinators::i;
    ///
    /// assert_eq!(app(i(), zero()).eval(), Ok(zero()));
    /// ```
    pub fn eval(self) -> Result<Term, Error> {
        let (lhs, rhs) = try!(self.unapp());

        apply(lhs, &rhs)
    }

    /// Performs a single β-reduction on `self` with the specified evaluation `Order`.
    ///
    /// # Example
    ///
    /// ```
    /// use lambda_calculus::arithmetic::succ;
    /// use lambda_calculus::reduction::Order;
    ///
    /// let mut succ_one = succ().app(1.into());
    /// succ_one.beta_once(&Order::Normal);
    ///
    /// assert_eq!(succ_one, succ().apply(&1.into()).unwrap());
    /// ```
    pub fn beta_once(&mut self, order: &Order) {
        self.beta_once_indicative(order);
    }

    fn beta_once_indicative(&mut self, order: &Order) -> bool {
        match *order {
            Normal       => self._beta_once_normal(0),
            CallByName   => self._beta_once_call_by_name(),
            HeadSpine    => self._beta_once_head_spine(0, true),
            Applicative  => self._beta_once_applicative(0),
            CallByValue  => self._beta_once_call_by_value(),
            HybridNormal => {
                self._beta_once_head_spine(0, true);
                self._beta_once_normal(0)
            },
            HybridApplicative => self._beta_once_hybrid_applicative(0)
        }
    }

    fn eval_with_info(&mut self, depth: u32) -> bool {
        if SHOW_REDUCTIONS { print!("    {} reduces to ", show_precedence(self, 0, depth)) };
        let copy = self.clone();
        *self = copy.eval().unwrap();
        if SHOW_REDUCTIONS { println!("{}", show_precedence(self, 0, depth)) };
        true
    }

    // the return value indicates if reduction was performed
    fn _beta_once_normal(&mut self, depth: u32) -> bool {
        match *self {
            Var(_) => false,
            Abs(_) => self.unabs_ref_mut().unwrap()._beta_once_normal(depth + 1),
            App(_, _) => {
                if self.lhs_ref().unwrap().unabs_ref().is_ok() {
                    self.eval_with_info(depth)
                } else {
                    self.lhs_ref_mut().unwrap()._beta_once_normal(depth) ||
                    self.rhs_ref_mut().unwrap()._beta_once_normal(depth)
                }
            }
        }
    }

    // the return value indicates if reduction was performed
    fn _beta_once_call_by_name(&mut self) -> bool {
        match *self {
            App(_, _) => {
                if self.lhs_ref().unwrap().unabs_ref().is_ok() {
                    self.eval_with_info(0)
                } else {
                    self.lhs_ref_mut().unwrap()._beta_once_call_by_name()
                }
            },
            _ => false
        }
    }

    // the return value indicates if reduction was performed
    fn _beta_once_head_spine(&mut self, depth: u32, is_head: bool) -> bool {
        match *self {
            Var(_) => false,
            Abs(_) => if is_head {
                self.unabs_ref_mut().unwrap()._beta_once_head_spine(depth + 1, is_head)
            } else {
                false
            },
            App(_, _) => {
                if self.lhs_ref().unwrap().unabs_ref().is_ok() {
                    self.eval_with_info(0)
                } else {
                    self.lhs_ref_mut().unwrap()._beta_once_head_spine(depth, is_head) ||
                    self.rhs_ref_mut().unwrap()._beta_once_head_spine(depth, false)
                }
            }
        }
    }

    // the return value indicates if reduction was performed
    fn _beta_once_applicative(&mut self, depth: u32) -> bool {
        match *self {
            Var(_) => false,
            Abs(_) => self.unabs_ref_mut().unwrap()._beta_once_applicative(depth + 1),
            App(_, _) => {
                if  self.lhs_ref().unwrap().unabs_ref().is_ok() &&
                   !self.rhs_ref().unwrap().is_beta_reducible(&Applicative)
                {
                    self.eval_with_info(depth)
                } else {
                    self.lhs_ref_mut().unwrap()._beta_once_applicative(depth) ||
                    self.rhs_ref_mut().unwrap()._beta_once_applicative(depth)
                }
            }
        }
    }

    // the return value indicates if reduction was performed
    fn _beta_once_call_by_value(&mut self) -> bool {
        match *self {
            App(_, _) => {
                if self.lhs_ref().unwrap().unabs_ref().is_ok() {
                    if self.rhs_ref_mut().unwrap().is_beta_reducible(&CallByValue) {
                        self.rhs_ref_mut().unwrap()._beta_once_call_by_value()
                    } else {
                        self.eval_with_info(0)
                    }
                } else {
                    self.rhs_ref_mut().unwrap()._beta_once_call_by_value()
                }
            },
            _ => false
        }
    }

    // the return value indicates if reduction was performed
    fn _beta_once_hybrid_applicative(&mut self, depth: u32) -> bool {
        match *self {
            Var(_) => false,
            Abs(_) => self.unabs_ref_mut().unwrap()._beta_once_hybrid_applicative(depth + 1),
            App(_, _) => {
                if self.lhs_ref().unwrap().unabs_ref().is_ok() {
                    if self.rhs_ref_mut().unwrap().is_beta_reducible(&CallByValue) {
                        self.rhs_ref_mut().unwrap()._beta_once_call_by_value()
                    } else {
                        self.eval_with_info(0)
                    }
                } else {
                    self.lhs_ref_mut().unwrap()._beta_once_hybrid_applicative(depth) ||
                    self.rhs_ref_mut().unwrap()._beta_once_hybrid_applicative(depth)
                }
            }
        }
    }

    /// Checks whether `self` is β-reducible under the specified evaluation `Order`.
    ///
    /// # Example
    ///
    /// ```
    /// use lambda_calculus::arithmetic::{succ, zero};
    /// use lambda_calculus::reduction::Order;
    ///
    /// let reducible     = succ().app(1.into());
    /// let not_reducible = zero();
    ///
    /// assert!(reducible.is_beta_reducible(&Order::Normal));
    /// assert!(!not_reducible.is_beta_reducible(&Order::Normal));
    /// ```
    pub fn is_beta_reducible(&self, order: &Order) -> bool {
        match *self {
            Var(_) => false,
            Abs(_) => match *order {
                Normal | Applicative => self.unabs_ref().unwrap().is_beta_reducible(order),
                _ => false
            },
            App(_, _) => {
                if self.lhs_ref().unwrap().unabs_ref().is_ok() {
                    true
                } else {
                    self.lhs_ref().unwrap().is_beta_reducible(order) ||
                    self.rhs_ref().unwrap().is_beta_reducible(order)
                }
            }
        }
    }

    /// Performs full β-reduction on `self` using the specified evaluation `Order`.
    ///
    /// # Example
    ///
    /// ```
    /// use lambda_calculus::arithmetic::pred;
    /// use lambda_calculus::reduction::Order;
    ///
    /// let mut pred_one = pred().app(1.into());
    /// pred_one.beta_full(&Order::Normal);
    ///
    /// assert_eq!(pred_one, 0.into());
    /// ```
    pub fn beta_full(&mut self, order: &Order) {
        loop {
            if SHOW_REDUCTIONS { println!("reducing {}", self) }
            if !self.beta_once_indicative(order) { break }
        }
        if SHOW_REDUCTIONS { println!("    doesn't reduce") }
    }
}

/// Performs full β-reduction on a `Term` using the specified evaluation `Order`, consuming its
/// argument in the process.
///
/// # Example
///
/// ```
/// use lambda_calculus::arithmetic::pred;
/// use lambda_calculus::reduction::{beta_full, Order};
///
/// let pred_one = pred().app(1.into());
///
/// assert_eq!(beta_full(pred_one, &Order::Normal), 0.into());
/// ```
pub fn beta_full(mut term: Term, order: &Order) -> Term {
    term.beta_full(order);
    term
}

/// Performs a single β-reduction on a `Term` using the specified evaluation `Order`, consuming its
/// argument in the process.
///
/// # Example
///
/// ```
/// use lambda_calculus::arithmetic::succ;
/// use lambda_calculus::reduction::{beta_once, Order};
///
/// let succ_one = succ().app(1.into());
///
/// assert_eq!(beta_once(succ_one, &Order::Normal), succ().apply(&1.into()).unwrap());
/// ```
pub fn beta_once(mut term: Term, order: &Order) -> Term {
    term.beta_once(order);
    term
}

#[cfg(test)]
mod test {
    use super::*;
    use parser::parse;
    use combinators::{i, y};

    #[test]
    fn normal_order() {
        let reduces_instantly = parse(&"(λλ1)((λλλ((32)1))(λλ2))").unwrap();
        assert_eq!(beta_full(reduces_instantly.clone(), &Normal),
                   beta_once(reduces_instantly, &Normal));

        let should_reduce = parse(&"(λ2)((λ111)(λ111))").unwrap();
        assert_eq!(beta_full(should_reduce, &Normal), Var(1))
    }

    #[test]
    fn call_by_name_order() {
        let mut expr = app(abs(app(i(), Var(1))), app(i(), i()));
        expr.beta_once(&CallByName);
        assert_eq!(expr, app(i(), app(i(), i())));
        expr.beta_once(&CallByName);
        assert_eq!(expr, app(i(), i()));
        expr.beta_once(&CallByName);
        assert_eq!(expr, i());
    }

    #[test]
    fn applicative_order() {
        let expr = parse(&"λ1(((λλλ1)1)((λλ21)1))").unwrap();
        assert_eq!(&format!("{}", beta_once(expr, &Applicative)), "λ1((λλ1)((λλ21)1))");

        let expands = parse(&"(λ2)((λ111)(λ111))").unwrap();
        assert_eq!(&format!("{}", beta_once(expands, &Applicative)), "(λ2)((λ111)(λ111)(λ111))")
    }

    #[test]
    fn call_by_value_order() {
        let mut expr = app(abs(app(i(), Var(1))), app(i(), i()));
        expr.beta_once(&CallByValue);
        assert_eq!(expr, app(abs(app(i(), Var(1))), i()));
        expr.beta_once(&CallByValue);
        assert_eq!(expr, app(i(), i()));
        expr.beta_once(&CallByValue);
        assert_eq!(expr, i());
    }

    #[test]
    fn reducibility() {
        assert!(y().is_beta_reducible(&Normal));
        assert!(y().is_beta_reducible(&Applicative));
        assert!(!y().is_beta_reducible(&CallByName));
        assert!(!y().is_beta_reducible(&CallByValue));
    }
}
<|endoftext|>


<commit_before>use {Errno, Result, NixPath};
use libc::{c_int, c_char};

#[cfg(all(target_os = "linux",
          any(target_arch = "x86",
              target_arch = "x86_64",
              target_arch = "arm")),
          )]
pub mod quota {
    use libc::{self, c_int};

    pub struct QuotaCmd(pub QuotaSubCmd, pub QuotaType);
    pub type QuotaSubCmd = c_int;

    impl QuotaCmd {
        pub fn as_int(&self) -> c_int {
            ((self.0 << 8) | (self.1 & 0x00ff)) as c_int
        }
    }

    // linux quota version >= 2
    pub const Q_SYNC:	QuotaSubCmd = 0x800001;
    pub const Q_QUOTAON:	QuotaSubCmd = 0x800002;
    pub const Q_QUOTAOFF:	QuotaSubCmd = 0x800003;
    pub const Q_GETFMT:	QuotaSubCmd = 0x800004;
    pub const Q_GETINFO:	QuotaSubCmd = 0x800005;
    pub const Q_SETINFO:	QuotaSubCmd = 0x800006;
    pub const Q_GETQUOTA:	QuotaSubCmd = 0x800007;
    pub const Q_SETQUOTA:	QuotaSubCmd = 0x800008;

    pub type QuotaType = c_int;

    pub const USRQUOTA:	QuotaType = 0;
    pub const GRPQUOTA:	QuotaType = 1;

    pub type QuotaFmt = c_int;

    pub const QFMT_VFS_OLD:	QuotaFmt = 1;
    pub const QFMT_VFS_V0:	QuotaFmt = 2;
    pub const QFMT_VFS_V1:  QuotaFmt = 4;

    libc_bitflags!(
        #[derive(Default)]
        pub struct QuotaValidFlags: u32 {
            QIF_BLIMITS;
            QIF_SPACE;
            QIF_ILIMITS;
            QIF_INODES;
            QIF_BTIME;
            QIF_ITIME;
            QIF_LIMITS;
            QIF_USAGE;
            QIF_TIMES;
            QIF_ALL;
        }
    );

    #[repr(C)]
    #[derive(Default,Debug,Copy,Clone)]
    pub struct Dqblk {
        pub bhardlimit: u64,
        pub bsoftlimit: u64,
        pub curspace:   u64,
        pub ihardlimit: u64,
        pub isoftlimit: u64,
        pub curinodes: u64,
        pub btime: u64,
        pub itime: u64,
        pub valid: QuotaValidFlags,
    }
}

mod ffi {
    use libc::{c_int, c_char};

    extern {
        pub fn quotactl(cmd: c_int, special: * const c_char, id: c_int, data: *mut c_char) -> c_int;
    }
}

use std::ptr;

fn quotactl<P: ?Sized + NixPath>(cmd: quota::QuotaCmd, special: Option<&P>, id: c_int, addr: *mut c_char) -> Result<()> {
    unsafe {
        Errno::clear();
        let res = try!(
            match special {
                Some(dev) => dev.with_nix_path(|path| ffi::quotactl(cmd.as_int(), path.as_ptr(), id, addr)),
                None => Ok(ffi::quotactl(cmd.as_int(), ptr::null(), id, addr)),
            }
        );

        Errno::result(res).map(drop)
    }
}

pub fn quotactl_on<P: ?Sized + NixPath>(which: quota::QuotaType, special: &P, format: quota::QuotaFmt, quota_file: &P) -> Result<()> {
    try!(quota_file.with_nix_path(|path| {
        let mut path_copy = path.to_bytes_with_nul().to_owned();
        let p: *mut c_char = path_copy.as_mut_ptr() as *mut c_char;
        quotactl(quota::QuotaCmd(quota::Q_QUOTAON, which), Some(special), format as c_int, p)
    }))
}

pub fn quotactl_off<P: ?Sized + NixPath>(which: quota::QuotaType, special: &P) -> Result<()> {
    quotactl(quota::QuotaCmd(quota::Q_QUOTAOFF, which), Some(special), 0, ptr::null_mut())
}

pub fn quotactl_sync<P: ?Sized + NixPath>(which: quota::QuotaType, special: Option<&P>) -> Result<()> {
    quotactl(quota::QuotaCmd(quota::Q_SYNC, which), special, 0, ptr::null_mut())
}

pub fn quotactl_get<P: ?Sized + NixPath>(which: quota::QuotaType, special: &P, id: c_int, dqblk: &mut quota::Dqblk) -> Result<()> {
    use std::mem;
    unsafe {
        quotactl(quota::QuotaCmd(quota::Q_GETQUOTA, which), Some(special), id, mem::transmute(dqblk))
    }
}

pub fn quotactl_set<P: ?Sized + NixPath>(which: quota::QuotaType, special: &P, id: c_int, dqblk: &quota::Dqblk) -> Result<()> {
    use std::mem;
    let mut dqblk_copy = *dqblk;
    unsafe {
        quotactl(quota::QuotaCmd(quota::Q_SETQUOTA, which), Some(special), id, mem::transmute(&mut dqblk_copy))
    }
}
<commit_msg>Use libc::quotactl<commit_after>use {Errno, Result, NixPath};
use libc::{self, c_int, c_char};

#[cfg(all(target_os = "linux",
          any(target_arch = "x86",
              target_arch = "x86_64",
              target_arch = "arm")),
          )]
pub mod quota {
    use libc::{self, c_int};

    pub struct QuotaCmd(pub QuotaSubCmd, pub QuotaType);
    pub type QuotaSubCmd = c_int;

    impl QuotaCmd {
        pub fn as_int(&self) -> c_int {
            ((self.0 << 8) | (self.1 & 0x00ff)) as c_int
        }
    }

    // linux quota version >= 2
    pub const Q_SYNC:	QuotaSubCmd = 0x800001;
    pub const Q_QUOTAON:	QuotaSubCmd = 0x800002;
    pub const Q_QUOTAOFF:	QuotaSubCmd = 0x800003;
    pub const Q_GETFMT:	QuotaSubCmd = 0x800004;
    pub const Q_GETINFO:	QuotaSubCmd = 0x800005;
    pub const Q_SETINFO:	QuotaSubCmd = 0x800006;
    pub const Q_GETQUOTA:	QuotaSubCmd = 0x800007;
    pub const Q_SETQUOTA:	QuotaSubCmd = 0x800008;

    pub type QuotaType = c_int;

    pub const USRQUOTA:	QuotaType = 0;
    pub const GRPQUOTA:	QuotaType = 1;

    pub type QuotaFmt = c_int;

    pub const QFMT_VFS_OLD:	QuotaFmt = 1;
    pub const QFMT_VFS_V0:	QuotaFmt = 2;
    pub const QFMT_VFS_V1:  QuotaFmt = 4;

    libc_bitflags!(
        #[derive(Default)]
        pub struct QuotaValidFlags: u32 {
            QIF_BLIMITS;
            QIF_SPACE;
            QIF_ILIMITS;
            QIF_INODES;
            QIF_BTIME;
            QIF_ITIME;
            QIF_LIMITS;
            QIF_USAGE;
            QIF_TIMES;
            QIF_ALL;
        }
    );

    #[repr(C)]
    #[derive(Default,Debug,Copy,Clone)]
    pub struct Dqblk {
        pub bhardlimit: u64,
        pub bsoftlimit: u64,
        pub curspace:   u64,
        pub ihardlimit: u64,
        pub isoftlimit: u64,
        pub curinodes: u64,
        pub btime: u64,
        pub itime: u64,
        pub valid: QuotaValidFlags,
    }
}

use std::ptr;

fn quotactl<P: ?Sized + NixPath>(cmd: quota::QuotaCmd, special: Option<&P>, id: c_int, addr: *mut c_char) -> Result<()> {
    unsafe {
        Errno::clear();
        let res = try!(
            match special {
                Some(dev) => dev.with_nix_path(|path| libc::quotactl(cmd.as_int(), path.as_ptr(), id, addr)),
                None => Ok(libc::quotactl(cmd.as_int(), ptr::null(), id, addr)),
            }
        );

        Errno::result(res).map(drop)
    }
}

pub fn quotactl_on<P: ?Sized + NixPath>(which: quota::QuotaType, special: &P, format: quota::QuotaFmt, quota_file: &P) -> Result<()> {
    try!(quota_file.with_nix_path(|path| {
        let mut path_copy = path.to_bytes_with_nul().to_owned();
        let p: *mut c_char = path_copy.as_mut_ptr() as *mut c_char;
        quotactl(quota::QuotaCmd(quota::Q_QUOTAON, which), Some(special), format as c_int, p)
    }))
}

pub fn quotactl_off<P: ?Sized + NixPath>(which: quota::QuotaType, special: &P) -> Result<()> {
    quotactl(quota::QuotaCmd(quota::Q_QUOTAOFF, which), Some(special), 0, ptr::null_mut())
}

pub fn quotactl_sync<P: ?Sized + NixPath>(which: quota::QuotaType, special: Option<&P>) -> Result<()> {
    quotactl(quota::QuotaCmd(quota::Q_SYNC, which), special, 0, ptr::null_mut())
}

pub fn quotactl_get<P: ?Sized + NixPath>(which: quota::QuotaType, special: &P, id: c_int, dqblk: &mut quota::Dqblk) -> Result<()> {
    use std::mem;
    unsafe {
        quotactl(quota::QuotaCmd(quota::Q_GETQUOTA, which), Some(special), id, mem::transmute(dqblk))
    }
}

pub fn quotactl_set<P: ?Sized + NixPath>(which: quota::QuotaType, special: &P, id: c_int, dqblk: &quota::Dqblk) -> Result<()> {
    use std::mem;
    let mut dqblk_copy = *dqblk;
    unsafe {
        quotactl(quota::QuotaCmd(quota::Q_SETQUOTA, which), Some(special), id, mem::transmute(&mut dqblk_copy))
    }
}
<|endoftext|>


<commit_before>//! An rope.
//!
//! A rope is an efficient data structure for large mutable strings. It's
//! essentially a binary tree whose leaves are strings.
//!
//! For more information, see the following resources:
//! + http://scienceblogs.com/goodmath/2009/01/26/ropes-twining-together-strings/
//! + https://www.ibm.com/developerworks/library/j-ropes/
//! + http://citeseer.ist.psu.edu/viewdoc/download?doi=10.1.1.14.9450&rep=rep1&type=pdf

#![feature(const_fn)]
#![feature(box_syntax, box_patterns)]

use std::cmp;
use std::ops;
use std::convert;

#[derive(Debug)]
pub struct Rope<T> {
    // can we get away with having these be of &str or will they need
    // to be string?
    root: Node<T>
}

use self::Node::*;

/// A `Node` in the `Rope`'s tree.
///
/// A `Node` is either a `Leaf` holding a vector of `T`, or a
/// a `Branch` concatenating together two `Node`s.
#[derive(Debug)]
enum Node<T> {
    /// A leaf node
    Leaf(Vec<T>)
  , /// A branch concatenating together `l`eft and `r`ight nodes.
    Branch {
        /// The length of this node
        len: usize
      , /// The weight of a node is the summed weight of its left subtree
        weight: usize
      , /// The left branch node
        left: Option<Box<Node<T>>>
      , /// The right branch node
        right: Option<Box<Node<T>>>
    }
}

impl<T> Node<T> {
    const fn none() -> Self {
        Branch { len: 0
               , weight: 0
               , left: None
               , right: None
               }
    }

    /// Concatenate two `Node`s to return a new `Branch` node.
    fn branch(left: Self, right: Self) -> Self {
        Branch { len: left.len() + right.len()
               , weight: left.weight()
               , left: Some(box left)
               , right: Some(box right)
        }
    }

    #[inline]
    fn leaf(data: Vec<T>) -> Self {
        Leaf(data)
    }

    /// Returns the height in the tree of a node
    #[inline]
    fn height(&self) -> usize {
        use std::cmp::max;

        match self {
            &Node::Leaf(_) => 1
          , &Node::Branch { ref left, ref right, ..} =>
                max( left.as_ref().map(Box::as_ref).map_or(0, Node::height)
                   , right.as_ref().map(Box::as_ref).map_or(0, Node::height)
                   ) + 1
            }
    }

    /// Returns the length of a node
    //  TODO: do we want to cache this?
    fn len(&self) -> usize {
        match self { &Node::Leaf(ref v) => v.len()
                   , &Node::Branch { ref left, ref right, .. } =>
                        left.as_ref().map(Box::as_ref).map_or(0, Node::len) +
                        right.as_ref().map(Box::as_ref).map_or(0, Node::len)
                    }
    }

    /// Returns the weight of a node
    fn weight (&self) -> usize {
        match self { &Node::Leaf(ref v) => v.len()
                   , &Node::Branch { ref left, .. } =>
                        left.as_ref().map(Box::as_ref).map_or(0, Node::weight)
                    }
    }
}

impl<T> Rope<T> {

    /// Returns a new empty Rope
    ///
    /// # Examples
    /// ```
    /// use an_rope::Rope;
    /// let mut an_rope = Rope::<u8>::new();
    /// assert_eq!(an_rope.len(), 0);
    /// ```
    pub const fn new() -> Rope<T> {
        Rope { root: Node::<T>::none() }
    }

    /// Returns the length of this Rope
    ///
    /// # Examples
    /// ```
    /// use an_rope::Rope;
    /// let mut an_empty_rope = Rope::new();
    /// assert_eq!(an_empty_rope.len(), 0);
    /// ```
    /// ```
    /// use an_rope::Rope;
    /// let mut an_empty_rope = Rope::from(String::from(""));
    /// assert_eq!(an_empty_rope.len(), 0);
    /// ```
    /// ```
    /// use an_rope::Rope;
    /// let mut an_rope = Rope::from(String::from("a string"));
    /// assert_eq!(an_rope.len(), "a string".len());
    /// ```
    pub fn len(&self) -> usize {
        // self.root.len()
        unimplemented!()
    }

    /// Appends a rope to the end of this Rope
    ///
    /// # Examples
    /// ```
    /// use an_rope::Rope;
    /// let mut an_rope = Rope::from(String::from("abcd"));
    /// an_rope.append(Rope::from(String::from("efgh")))
    /// assert_eq!(an_rope, Rope::from(String::from("abcdefgh")));
    /// ```
    pub fn append(&mut self, other: Rope<T>) {
        unimplemented!()
    }

    /// Prepends a rope to the front of this Rope
    ///
    /// # Examples
    /// ```
    /// use an_rope::Rope;
    /// let mut an_rope = Rope::from(String::from("efgh"));
    /// an_rope.preend(Rope::from(String::from("abcd")))
    /// assert_eq!(an_rope, Rope::from(String::from("abcdefgh")));
    /// ```
    pub fn prepend(&mut self, other: Rope<T>) {
        unimplemented!()
    }

    /// Splits the rope into two ropes at the given index.
    ///
    /// Consumes this rope.
    ///
    /// # Examples
    /// ```
    /// use an_rope::Rope;
    /// let mut an_rope = Rope::from(String::from("abcd"));
    /// let (ab, cd) = an_rope.split(2);
    /// assert_eq!(ab, Rope::from(String::from("ab")));
    /// assert_eq!(cd, Rope::from(String::from("cd")));
    /// ```
    pub fn split(self, index: usize) -> (Rope<T>, Rope<T>) {
        unimplemented!()
    }
}

impl<T> ops::Index<usize> for Node<T> {
    type Output = T;

    fn index(&self, i: usize) -> &T {
        // let len = self.len();
        // match self { &Node::Leaf(ref vec) => { &vec[i] }
        //             , &Node::Branch { right: Some(box ref r), .. } if len < i =>
        //                 &r[i - len]
        //             , &Node::Branch { left: Some(box ref l), .. } => &l[i]
        //             , &Node::Branch { left: None, right: None, .. } =>
        //                 panic!("Index out of bounds!")
        //             }
        unimplemented!()
    }
}

impl<T> convert::Into<Vec<T>> for Rope<T> {
    fn into(self) -> Vec<T> {
        unimplemented!()
    }

}

impl convert::From<String> for Rope<u8> {
    fn from(string: String) -> Rope<u8> {
        Rope {
            root: if string.len() == 0 { Node::none() }
                  else { Node::Leaf(string.into_bytes()) }
        }
    }
}

//-- comparisons ----------------------------------------------------
impl<T> cmp::PartialEq for Rope<T> {
    fn eq(&self, other: &Rope<T>) -> bool {
        unimplemented!()
    }
}

impl<T> cmp::PartialEq<str> for Rope<T> {
    fn eq(&self, other: &str) -> bool {
        unimplemented!()
    }
}

//-- concatenation --------------------------------------------------
impl ops::AddAssign for Rope<u8> {

    /// Concatenate two `Rope`s.
    ///
    /// # Examples
    /// ```
    /// let mut rope = Rope::from(String::from("ab"));
    /// rope += Rope::from(String::from("cd"));
    /// assert_eq!(rope, Rope::from(String::from("abcd")));
    /// ```
    #[inline]
    fn add_assign(&mut self, other: Rope<u8>) {
        self.append(other)
    }
}

impl ops::AddAssign<String> for Rope<u8> {

    /// Concatenate a `String` onto a `Rope`
    ///
    /// # Examples
    /// ```
    /// let mut rope = Rope::from(String::from("ab"));
    /// rope += String::from("cd");
    /// assert_eq!(rope, Rope::from(String::from("abcd")));
    /// ```
    #[inline]
    fn add_assign(&mut self, string: String) {
        self.append(Rope::from(string))
    }
}

impl<'a> ops::AddAssign<&'a str> for Rope<u8> {

    /// Concatenate an `&str` onto a `Rope`
    ///
    /// # Examples
    /// ```
    /// let mut rope = Rope::from(String::from("ab"));
    /// rope += String::from("cd");
    /// assert_eq!(rope, Rope::from(String::from("abcd")));
    /// ```
    #[inline]
    fn add_assign(&mut self, string: &'a str) {
        self.append(Rope::from(string.to_owned()))
    }
}

impl<T> ops::Index<usize> for Rope<T> {
    type Output = T;

    /// Recursively index the Rope to return the `i` th character.
    ///
    /// # Examples
    /// ```
    /// use an_rope::Rope;
    /// let an_rope = Rope::from(String::from("abcd"));
    /// assert_eq!(&an_rope[0], "a");
    /// assert_eq!(&an_rope[1], "b");
    /// assert_eq!(&an_rope[2], "c");
    /// assert_eq!(&an_rope[3], "d");
    /// ```
    ///
    /// # Time complexity
    /// _O_(log _n_)
    ///
    #[inline]
    fn index(&self, i: usize) -> &T {
        &self.root[i]
    }
}

//-- slicing operators ----------------------------------------------
impl<T> ops::Index<ops::Range<usize>> for Rope<T> {
    type Output = [T];

    // Index a substring
    fn index(&self, i: ops::Range<usize>) -> &[T] {
        unimplemented!()
    }
}

impl<T> ops::Index<ops::RangeTo<usize>> for Rope<T> {
    type Output = [T];

    fn index(&self, i: ops::RangeTo<usize>) -> &[T] {
        unimplemented!()
    }
}

impl<T> ops::Index<ops::RangeFrom<usize>> for Rope<T> {
    type Output = [T];

    fn index(&self, i: ops::RangeFrom<usize>) -> &[T] {
        unimplemented!()
    }
}

impl<T> ops::IndexMut<ops::Range<usize>> for Rope<T> {
    fn index_mut(&mut self, i: ops::Range<usize>) -> &mut [T] {
        unimplemented!()
    }
}

impl<T> ops::IndexMut<ops::RangeTo<usize>> for Rope<T> {
    fn index_mut(&mut self, i: ops::RangeTo<usize>) -> &mut [T] {
        unimplemented!()
    }
}

impl<T> ops::IndexMut<ops::RangeFrom<usize>> for Rope<T> {
    fn index_mut(&mut self, i: ops::RangeFrom<usize>) -> &mut [T] {
        unimplemented!()
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}
<commit_msg>rope: add destructive & non-destructive concat fs & operators<commit_after>//! An rope.
//!
//! A rope is an efficient data structure for large mutable strings. It's
//! essentially a binary tree whose leaves are strings.
//!
//! For more information, see the following resources:
//! + http://scienceblogs.com/goodmath/2009/01/26/ropes-twining-together-strings/
//! + https://www.ibm.com/developerworks/library/j-ropes/
//! + http://citeseer.ist.psu.edu/viewdoc/download?doi=10.1.1.14.9450&rep=rep1&type=pdf

#![feature(const_fn)]
#![feature(box_syntax, box_patterns)]

use std::cmp;
use std::ops;
use std::convert;

#[derive(Debug)]
pub struct Rope<T> {
    // can we get away with having these be of &str or will they need
    // to be string?
    root: Node<T>
}

use self::Node::*;

/// A `Node` in the `Rope`'s tree.
///
/// A `Node` is either a `Leaf` holding a vector of `T`, or a
/// a `Branch` concatenating together two `Node`s.
#[derive(Debug)]
enum Node<T> {
    /// A leaf node
    Leaf(Vec<T>)
  , /// A branch concatenating together `l`eft and `r`ight nodes.
    Branch {
        /// The length of this node
        len: usize
      , /// The weight of a node is the summed weight of its left subtree
        weight: usize
      , /// The left branch node
        left: Option<Box<Node<T>>>
      , /// The right branch node
        right: Option<Box<Node<T>>>
    }
}

impl<T> Node<T> {
    const fn none() -> Self {
        Branch { len: 0
               , weight: 0
               , left: None
               , right: None
               }
    }

    /// Concatenate two `Node`s to return a new `Branch` node.
    fn branch(left: Self, right: Self) -> Self {
        Branch { len: left.len() + right.len()
               , weight: left.weight()
               , left: Some(box left)
               , right: Some(box right)
        }
    }

    #[inline]
    fn leaf(data: Vec<T>) -> Self {
        Leaf(data)
    }

    /// Returns the height in the tree of a node
    #[inline]
    fn height(&self) -> usize {
        use std::cmp::max;

        match self {
            &Node::Leaf(_) => 1
          , &Node::Branch { ref left, ref right, ..} =>
                max( left.as_ref().map(Box::as_ref).map_or(0, Node::height)
                   , right.as_ref().map(Box::as_ref).map_or(0, Node::height)
                   ) + 1
            }
    }

    /// Returns the length of a node
    //  TODO: do we want to cache this?
    fn len(&self) -> usize {
        match self { &Node::Leaf(ref v) => v.len()
                   , &Node::Branch { ref left, ref right, .. } =>
                        left.as_ref().map(Box::as_ref).map_or(0, Node::len) +
                        right.as_ref().map(Box::as_ref).map_or(0, Node::len)
                    }
    }

    /// Returns the weight of a node
    fn weight (&self) -> usize {
        match self { &Node::Leaf(ref v) => v.len()
                   , &Node::Branch { ref left, .. } =>
                        left.as_ref().map(Box::as_ref).map_or(0, Node::weight)
                    }
    }
}

impl<T> ops::Add for Node<T> {
    type Output = Self;
    /// Concatenate two `Node`s, returning a `Branch` node.
    fn add(self, right: Self) -> Self { Node::branch(self, right) }
}

impl<T> Rope<T> {

    /// Returns a new empty Rope
    ///
    /// # Examples
    /// ```
    /// use an_rope::Rope;
    /// let mut an_rope = Rope::<u8>::new();
    /// assert_eq!(an_rope.len(), 0);
    /// ```
    pub const fn new() -> Rope<T> {
        Rope { root: Node::<T>::none() }
    }

    /// Returns the length of this Rope
    ///
    /// # Examples
    /// ```
    /// use an_rope::Rope;
    /// let mut an_empty_rope = Rope::new();
    /// assert_eq!(an_empty_rope.len(), 0);
    /// ```
    /// ```
    /// use an_rope::Rope;
    /// let mut an_empty_rope = Rope::from(String::from(""));
    /// assert_eq!(an_empty_rope.len(), 0);
    /// ```
    /// ```
    /// use an_rope::Rope;
    /// let mut an_rope = Rope::from(String::from("a string"));
    /// assert_eq!(an_rope.len(), "a string".len());
    /// ```
    pub fn len(&self) -> usize {
        // self.root.len()
        unimplemented!()
    }

    /// Appends a `Rope` to the end of this `Rope`, returning a new `Rope`
    ///
    /// Note that this is equivalent to using the `+` operator.
    ///
    /// # Examples
    /// ```
    /// use an_rope::Rope;
    /// let an_rope = Rope::from(String::from("abcd"));
    /// let another_rope = an_rope.merge(Rope::from(String::from("efgh")))
    /// assert_eq!(another_rope, Rope::from(String::from("abcdefgh")));
    /// ```
    pub fn merge(&self, other: &Rope<T>) -> Rope<T> {
        unimplemented!()
    }

    /// Appends a `Rope` to the end of this `Rope`, updating it in place.
    ///
    /// Note that this is equivalent to using the `+=` operator.
    ///
    /// # Examples
    /// ```
    /// use an_rope::Rope;
    /// let mut an_rope = Rope::from(String::from("abcd"));
    /// an_rope.update(Rope::from(String::from("efgh")))
    /// assert_eq!(an_rope, Rope::from(String::from("abcdefgh")));
    /// ```
    pub fn update(&mut self, other: Rope<T>) {
        unimplemented!()
    }

    /// Splits the rope into two ropes at the given index.
    ///
    /// Consumes this rope.
    ///
    /// # Examples
    /// ```
    /// use an_rope::Rope;
    /// let mut an_rope = Rope::from(String::from("abcd"));
    /// let (ab, cd) = an_rope.split(2);
    /// assert_eq!(ab, Rope::from(String::from("ab")));
    /// assert_eq!(cd, Rope::from(String::from("cd")));
    /// ```
    pub fn split(self, index: usize) -> (Rope<T>, Rope<T>) {
        unimplemented!()
    }
}

impl<T> ops::Index<usize> for Node<T> {
    type Output = T;

    fn index(&self, i: usize) -> &T {
        // let len = self.len();
        // match self { &Node::Leaf(ref vec) => { &vec[i] }
        //             , &Node::Branch { right: Some(box ref r), .. } if len < i =>
        //                 &r[i - len]
        //             , &Node::Branch { left: Some(box ref l), .. } => &l[i]
        //             , &Node::Branch { left: None, right: None, .. } =>
        //                 panic!("Index out of bounds!")
        //             }
        unimplemented!()
    }
}

impl<T> convert::Into<Vec<T>> for Rope<T> {
    fn into(self) -> Vec<T> {
        unimplemented!()
    }

}

impl convert::From<String> for Rope<u8> {
    fn from(string: String) -> Rope<u8> {
        Rope {
            root: if string.len() == 0 { Node::none() }
                  else { Node::Leaf(string.into_bytes()) }
        }
    }
}

//-- comparisons ----------------------------------------------------
impl<T> cmp::PartialEq for Rope<T> {
    fn eq(&self, other: &Rope<T>) -> bool {
        unimplemented!()
    }
}

impl<T> cmp::PartialEq<str> for Rope<T> {
    fn eq(&self, other: &str) -> bool {
        unimplemented!()
    }
}

//-- concatenation --------------------------------------------------
impl<'a, T> ops::Add for &'a Rope<T> {
    type Output = Rope<T>;
    /// Non-destructively concatenate two `Rope`s, returning a new `Rope`.
    ///
    /// # Examples
    /// ```
    /// let rope = Rope::from(String::from("ab"));
    /// assert_eq!( &rope + &Rope::from(String::from("cd"))
    ///           , Rope::from(String::from("abcd")));
    /// ```
    #[inline] fn add(self, other: Self) -> Rope<T> { self.merge(other) }

}

impl<T> ops::Add for Rope<T> {
    type Output = Rope<T>;
    /// Non-destructively concatenate two `Rope`s, returning a new `Rope`.
    ///
    /// # Examples
    /// ```
    /// let rope = Rope::from(String::from("ab"));
    /// assert_eq!( rope + Rope::from(String::from("cd"))
    ///           , Rope::from(String::from("abcd")));
    /// ```
    #[inline] fn add(self, other: Self) -> Rope<T> { self.merge(&other) }
}

impl ops::Add<String> for Rope<u8> {
    type Output = Rope<u8>;
    /// Non-destructively concatenate a `Rope` and a `String`.
    ///
    /// Returns a new `Rope`
    ///
    /// # Examples
    /// ```
    /// let rope = Rope::from(String::from("ab"));
    /// assert_eq!( rope + String::from("cd"))
    ///           , Rope::from(String::from("abcd")));
    /// ```
    #[inline] fn add(self, other: String) -> Rope<u8> {
         self.merge(&Rope::from(other))
    }
}

impl<'a, 'b> ops::Add<&'b str> for &'a Rope<u8> {
    type Output = Rope<u8>;
    /// Non-destructively concatenate a `Rope` and an `&str`.
    ///
    /// Returns a new `Rope`
    ///
    /// # Examples
    /// ```
    /// let rope = Rope::from(String::from("ab"));
    /// assert_eq!( &rope + "cd")
    ///           , Rope::from(String::from("abcd")));
    /// ```
    #[inline] fn add(self, other: &'b str) -> Rope<u8> {
         self.merge(&Rope::from(other.to_owned()))
     }

}

impl<'a> ops::Add<&'a str> for Rope<u8> {
    type Output = Rope<u8>;
    /// Non-destructively concatenate a `Rope` and an `&str`.
    ///
    /// Returns a new `Rope`
    ///
    /// # Examples
    /// ```
    /// let rope = Rope::from(String::from("ab"));
    /// assert_eq!( rope + "cd")
    ///           , Rope::from(String::from("abcd")));
    /// ```
    #[inline] fn add(self, other: &'a str) -> Rope<u8> {
         self.merge(&Rope::from(other.to_owned()))
     }

}

impl<T> ops::AddAssign for Rope<T> {

    /// Concatenate two `Rope`s mutably.
    ///
    /// # Examples
    /// ```
    /// let mut rope = Rope::from(String::from("ab"));
    /// rope += Rope::from(String::from("cd"));
    /// assert_eq!(rope, Rope::from(String::from("abcd")));
    /// ```
    #[inline]
    fn add_assign(&mut self, other: Rope<T>) {
        self.update(other)
    }
}

impl ops::AddAssign<String> for Rope<u8> {

    /// Concatenate a `String` onto a `Rope` mutably.
    ///
    /// # Examples
    /// ```
    /// let mut rope = Rope::from(String::from("ab"));
    /// rope += String::from("cd");
    /// assert_eq!(rope, Rope::from(String::from("abcd")));
    /// ```
    #[inline]
    fn add_assign(&mut self, string: String) {
        self.update(Rope::from(string))
    }
}

impl<'a> ops::AddAssign<&'a str> for Rope<u8> {

    /// Concatenate an `&str` onto a `Rope` mutably.
    ///
    /// # Examples
    /// ```
    /// let mut rope = Rope::from(String::from("ab"));
    /// rope += String::from("cd");
    /// assert_eq!(rope, Rope::from(String::from("abcd")));
    /// ```
    #[inline]
    fn add_assign(&mut self, string: &'a str) {
        self.update(Rope::from(string.to_owned()))
    }
}

impl<T> ops::Index<usize> for Rope<T> {
    type Output = T;

    /// Recursively index the Rope to return the `i` th character.
    ///
    /// # Examples
    /// ```
    /// use an_rope::Rope;
    /// let an_rope = Rope::from(String::from("abcd"));
    /// assert_eq!(&an_rope[0], "a");
    /// assert_eq!(&an_rope[1], "b");
    /// assert_eq!(&an_rope[2], "c");
    /// assert_eq!(&an_rope[3], "d");
    /// ```
    ///
    /// # Time complexity
    /// _O_(log _n_)
    ///
    #[inline]
    fn index(&self, i: usize) -> &T {
        &self.root[i]
    }
}

//-- slicing operators ----------------------------------------------
impl<T> ops::Index<ops::Range<usize>> for Rope<T> {
    type Output = [T];

    // Index a substring
    fn index(&self, i: ops::Range<usize>) -> &[T] {
        unimplemented!()
    }
}

impl<T> ops::Index<ops::RangeTo<usize>> for Rope<T> {
    type Output = [T];

    fn index(&self, i: ops::RangeTo<usize>) -> &[T] {
        unimplemented!()
    }
}

impl<T> ops::Index<ops::RangeFrom<usize>> for Rope<T> {
    type Output = [T];

    fn index(&self, i: ops::RangeFrom<usize>) -> &[T] {
        unimplemented!()
    }
}

impl<T> ops::IndexMut<ops::Range<usize>> for Rope<T> {
    fn index_mut(&mut self, i: ops::Range<usize>) -> &mut [T] {
        unimplemented!()
    }
}

impl<T> ops::IndexMut<ops::RangeTo<usize>> for Rope<T> {
    fn index_mut(&mut self, i: ops::RangeTo<usize>) -> &mut [T] {
        unimplemented!()
    }
}

impl<T> ops::IndexMut<ops::RangeFrom<usize>> for Rope<T> {
    fn index_mut(&mut self, i: ops::RangeFrom<usize>) -> &mut [T] {
        unimplemented!()
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}
<|endoftext|>


<commit_before>#![cfg(feature = "serde")]

extern crate serde;

use EnumMap;
use Internal;

use self::serde::ser::{Serialize, Serializer, SerializeMap};
use self::serde::de::{self, Deserialize, Deserializer, Error, MapAccess};

use core::fmt;
use core::marker::PhantomData;

impl<K: Internal<V> + Serialize, V: Serialize> Serialize for EnumMap<K, V> {
    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        let mut map = serializer.serialize_map(Some(self.len()))?;
        for (key, value) in self {
            map.serialize_entry(&key, value)?;
        }
        map.end()
    }
}

impl<'de, K, V> Deserialize<'de> for EnumMap<K, V>
where
    K: Internal<V>
        + Internal<Option<V>>
        + Deserialize<'de>,
    V: Deserialize<'de>,
{
    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
        deserializer.deserialize_map(Visitor(PhantomData))
    }
}

struct Visitor<K: Internal<V>, V>(PhantomData<EnumMap<K, V>>);

impl<'de, K, V> de::Visitor<'de> for Visitor<K, V>
where
    K: Internal<V>
        + Internal<Option<V>>
        + Deserialize<'de>,
    V: Deserialize<'de>,
{
    type Value = EnumMap<K, V>;

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "a map")
    }

    fn visit_map<M: MapAccess<'de>>(self, mut access: M) -> Result<Self::Value, M::Error> {
        let mut entries = EnumMap::from(|_| None);
        while let Some((key, value)) = access.next_entry()? {
            entries[key] = Some(value);
        }
        for (_, value) in &entries {
            if value.is_none() {
                return Err(M::Error::custom("key not specified"));
            }
        }
        Ok(EnumMap::from(|key| entries[key].take().unwrap()))
    }
}
<commit_msg>Document serde implementations just like ordermap<commit_after>#![cfg(feature = "serde")]

extern crate serde;

use EnumMap;
use Internal;

use self::serde::ser::{Serialize, Serializer, SerializeMap};
use self::serde::de::{self, Deserialize, Deserializer, Error, MapAccess};

use core::fmt;
use core::marker::PhantomData;

/// Requires crate feature `"serde"`
impl<K: Internal<V> + Serialize, V: Serialize> Serialize for EnumMap<K, V> {
    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        let mut map = serializer.serialize_map(Some(self.len()))?;
        for (key, value) in self {
            map.serialize_entry(&key, value)?;
        }
        map.end()
    }
}

/// Requires crate feature `"serde"`
impl<'de, K, V> Deserialize<'de> for EnumMap<K, V>
where
    K: Internal<V>
        + Internal<Option<V>>
        + Deserialize<'de>,
    V: Deserialize<'de>,
{
    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
        deserializer.deserialize_map(Visitor(PhantomData))
    }
}

struct Visitor<K: Internal<V>, V>(PhantomData<EnumMap<K, V>>);

impl<'de, K, V> de::Visitor<'de> for Visitor<K, V>
where
    K: Internal<V>
        + Internal<Option<V>>
        + Deserialize<'de>,
    V: Deserialize<'de>,
{
    type Value = EnumMap<K, V>;

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "a map")
    }

    fn visit_map<M: MapAccess<'de>>(self, mut access: M) -> Result<Self::Value, M::Error> {
        let mut entries = EnumMap::from(|_| None);
        while let Some((key, value)) = access.next_entry()? {
            entries[key] = Some(value);
        }
        for (_, value) in &entries {
            if value.is_none() {
                return Err(M::Error::custom("key not specified"));
            }
        }
        Ok(EnumMap::from(|key| entries[key].take().unwrap()))
    }
}
<|endoftext|>