1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
// Copyright (C) 2019-2021 Aleo Systems Inc.
// This file is part of the Leo library.

// The Leo library is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// The Leo library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.

use crate::PositiveNumber;
use leo_input::types::ArrayDimensions as InputArrayDimensions;

use serde::{Deserialize, Serialize};
use std::fmt;

/// A vector of positive numbers that represent array dimensions.
/// Can be used in an array [`Type`] or an array initializer [`Expression`].
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq, Default, Hash)]
pub struct ArrayDimensions(pub Vec<PositiveNumber>);

impl ArrayDimensions {
    ///
    /// Appends a vector of array dimensions to the self array dimensions.
    ///
    pub fn append(&mut self, other: &mut ArrayDimensions) {
        self.0.append(&mut other.0)
    }

    ///
    /// Returns the array dimensions as strings.
    ///
    pub fn to_strings(&self) -> Vec<String> {
        self.0.iter().map(|number| number.to_string()).collect()
    }

    ///
    /// Returns `true` if the all array dimensions have been removed.
    ///
    /// This method is called after repeated calls to `remove_first`.
    ///
    pub fn is_empty(&self) -> bool {
        self.0.is_empty()
    }

    ///
    /// Returns `true` if there is an array dimension equal to zero.
    ///
    pub fn is_zero(&self) -> bool {
        self.0.iter().any(|number| number.is_zero())
    }

    ///
    /// Returns the first dimension of the array.
    ///
    pub fn first(&self) -> Option<&PositiveNumber> {
        self.0.first()
    }

    ///
    /// Attempts to remove the first dimension from the array.
    ///
    /// If the first dimension exists, then remove and return `Some(PositiveNumber)`.
    /// If the first dimension does not exist, then return `None`.
    ///
    pub fn remove_first(&mut self) -> Option<PositiveNumber> {
        // If there are no dimensions in the array, then return None.
        self.0.first()?;

        // Remove the first dimension.
        let removed = self.0.remove(0);

        // Return the first dimension.
        Some(removed)
    }

    ///
    /// Attempts to remove the last dimension from the array.
    ///
    /// If the last dimension exists, then remove and return `Some(PositiveNumber)`.
    /// If the last dimension does not exist, then return `None`.
    ///
    pub fn remove_last(&mut self) -> Option<PositiveNumber> {
        self.0.pop()
    }
}

/// Create a new [`ArrayDimensions`] from a [`InputArrayDimensions`] in a Leo program file.
impl<'ast> From<InputArrayDimensions<'ast>> for ArrayDimensions {
    fn from(dimensions: InputArrayDimensions<'ast>) -> Self {
        Self(match dimensions {
            InputArrayDimensions::Single(single) => vec![PositiveNumber::from(single.number)],
            InputArrayDimensions::Multiple(multiple) => {
                multiple.numbers.into_iter().map(PositiveNumber::from).collect()
            }
        })
    }
}

impl fmt::Display for ArrayDimensions {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.0.len() == 1 {
            // Write dimensions without parenthesis.
            write!(f, "{}", self.0[0])
        } else {
            // Write dimensions with parenthesis.
            let dimensions = self.0.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(", ");

            write!(f, "({})", dimensions)
        }
    }
}