continue implementation
[pspp] / rust / src / dictionary.rs
index f9886641f7f582398627b9ab937cf63b1ab8caa3..e9eca118abe71218f8122e70629eccfcf820500f 100644 (file)
@@ -8,10 +8,10 @@ use encoding_rs::Encoding;
 use indexmap::IndexSet;
 
 use crate::{
-    cooked::{MissingValues, Value, VarWidth},
-    format::Format,
+    cooked::{Value, VarWidth},
+    format::Spec,
     identifier::{ByIdentifier, HasIdentifier, Identifier},
-    raw::{CategoryLabels, Alignment, Measure},
+    raw::{Alignment, CategoryLabels, Measure, MissingValues, VarType},
 };
 
 pub type DictIndex = usize;
@@ -50,6 +50,14 @@ impl Dictionary {
         }
     }
 
+    pub fn add_var(&mut self, variable: Variable) -> Result<(), ()> {
+        if self.variables.insert(ByIdentifier::new(variable)) {
+            Ok(())
+        } else {
+            Err(())
+        }
+    }
+
     pub fn reorder_var(&mut self, from_index: DictIndex, to_index: DictIndex) {
         if from_index != to_index {
             self.variables.move_index(from_index, to_index);
@@ -187,16 +195,48 @@ pub enum Role {
     Split,
 }
 
+impl Default for Role {
+    fn default() -> Self {
+        Self::Input
+    }
+}
+
+pub enum DictClass {
+    Ordinary,
+    System,
+    Scratch,
+}
+
+impl DictClass {
+    pub fn from_identifier(id: &Identifier) -> Self {
+        if id.0.starts_with('$') {
+            Self::System
+        } else if id.0.starts_with('#') {
+            Self::Scratch
+        } else {
+            Self::Ordinary
+        }
+    }
+
+    pub fn must_leave(self) -> bool {
+        match self {
+            DictClass::Ordinary => false,
+            DictClass::System => false,
+            DictClass::Scratch => true,
+        }
+    }
+}
+
 #[derive(Clone, Debug)]
 pub struct Variable {
     pub name: Identifier,
     pub width: VarWidth,
     pub missing_values: MissingValues,
-    pub print_format: Format,
-    pub write_format: Format,
+    pub print_format: Spec,
+    pub write_format: Spec,
     pub value_labels: HashMap<Value, String>,
     pub label: Option<String>,
-    pub measure: Measure,
+    pub measure: Option<Measure>,
     pub role: Role,
     pub display_width: u32,
     pub alignment: Alignment,
@@ -205,6 +245,29 @@ pub struct Variable {
     pub attributes: HashSet<ByIdentifier<Attribute>>,
 }
 
+impl Variable {
+    pub fn new(name: Identifier, width: VarWidth) -> Self {
+        let var_type = VarType::from_width(width);
+        let leave = DictClass::from_identifier(&name).must_leave();
+        Self {
+            name,
+            width,
+            missing_values: MissingValues::default(),
+            print_format: Spec::default_for_width(width),
+            write_format: Spec::default_for_width(width),
+            value_labels: HashMap::new(),
+            label: None,
+            measure: Measure::default_for_type(var_type),
+            role: Role::default(),
+            display_width: width.default_display_width(),
+            alignment: Alignment::default_for_type(var_type),
+            leave,
+            short_names: Vec::new(),
+            attributes: HashSet::new()
+        }
+    }
+}
+
 impl HasIdentifier for Variable {
     fn identifier(&self) -> &Identifier {
         &self.name