base_custom/
char.rs

1use std::collections::HashMap;
2use crate::util::unique;
3use crate::BaseCustom;
4use std::ops::Range;
5use std::fmt;
6
7impl BaseCustom<char> {
8
9  /// 'new' creates a new BaseCustom instance and propogates the values for converting
10  /// numeric bases.
11  ///
12  /// `new` for `BaseCustom<char>` requires a `Vec<char>` as its parameters and units
13  /// for measuring the custom numeric base will only be one character long each.
14  pub fn new(chars: Vec<char>) -> BaseCustom<char> {
15    if chars.iter().count() < 2 { panic!("Too few numeric units! Provide two or more.") }
16    if chars.iter().count() > 255 { panic!("Too many numeric units!") }
17
18    let chars = unique(chars);
19
20    let mut mapped = HashMap::with_capacity(chars.iter().count());
21    for (i,c) in chars.iter().enumerate() {
22      mapped.insert(c.clone(), i as u8);
23    }
24    BaseCustom::<char> {
25      primitives: chars.clone(),
26      primitives_hash: mapped,
27      base: chars.iter().count() as u64,
28      delim: None,
29    }
30  }
31
32  /// `gen` returns a String computed from the character mapping and 
33  /// positional values the given u64 parameter evalutes to for your
34  /// custom base
35  ///
36  /// # Example
37  /// ```
38  /// use base_custom::BaseCustom;
39  ///
40  /// let base2 = BaseCustom::<char>::new(vec!['0','1']);
41  /// assert_eq!(base2.gen(3), "11");
42  /// ```
43  ///
44  /// # Output
45  /// ```text
46  /// "11"
47  /// ```
48  pub fn gen(&self, input_val: u64) -> String {
49    if input_val == 0 {
50      return format!("{}", self.primitives[0]);
51    }
52    let mut number = input_val;
53    let mut result = String::new();
54    loop {
55      if number == 0 { break };
56      result.insert(0, self.primitives[(number % self.base) as usize]);
57      number = number/self.base;
58    };
59    format!("{}", result)
60  }
61
62  /// `char` returns a char straight from the character mapping.
63  /// decimal value must be within character range for a Some result.
64  ///
65  /// # Example
66  /// ```
67  /// use base_custom::BaseCustom;
68  ///
69  /// let base10 = BaseCustom::<char>::new("0123456789".chars().collect());
70  /// assert_eq!(base10.char(9), Some('9'));
71  /// ```
72  ///
73  /// # Output
74  /// ```text
75  /// '9'
76  /// ```
77  pub fn char(&self, input_val: usize) -> Option<char> {
78    if input_val > self.primitives.len() { return None }
79    Some(self.primitives[input_val])
80  }
81
82
83  /// `decimal` returns a u64 value on computed from the units that form
84  /// the custom base.
85  ///
86  /// # Example
87  /// ```
88  /// use base_custom::BaseCustom;
89  ///
90  /// let base2 = BaseCustom::<char>::new(vec!['0','1']);
91  /// assert_eq!(base2.decimal("00011"), 3);
92  /// ```
93  ///
94  /// # Output
95  /// ```text
96  /// 3
97  /// ```
98  pub fn decimal<S>(&self, input_val: S) -> u64
99    where S: Into<String> {
100    let input_val = input_val.into();
101
102    input_val.chars().rev().enumerate().fold(0, |sum, (i, chr)|
103      sum + (self.primitives_hash[&chr] as u64) * self.base.pow(i as u32)
104    )
105  }
106
107  /// Returns the zero value of your custom base
108  pub fn zero(&self) -> &char {
109    &self.primitives[0]
110  }
111
112  /// Returns the one value of your custom base
113  pub fn one(&self) -> &char {
114    &self.primitives[1]
115  }
116
117  /// Returns the nth value of your custom base
118  /// 
119  /// Like most indexing operations, the count starts from zero, so nth(0) returns the first value,
120  /// nth(1) the second, and so on.
121  pub fn nth(&self, pos: usize) -> Option<&char> {
122    if pos < self.base as usize {
123      Some(&self.primitives[pos])
124    } else {
125      None
126    }
127  }
128
129  /// Create a custom numeric base from an ascii range of ordinal values
130  ///
131  /// This method currently restricts the ascii character range of the
132  /// 95 typical characters starting from 32 and ending with 127.  If you'd
133  /// like to use characters outside of this range please use the `new` method.
134  pub fn from_ordinal_range(range: Range<u32>) -> BaseCustom<char> {
135    let min = std::cmp::max(32, range.start);
136    let max = std::cmp::min(127, range.end);
137    let mut chars: Vec<char> = Vec::with_capacity(std::cmp::min(range.len(), 95));
138    for chr in min..max {
139      chars.push(std::char::from_u32(chr).unwrap());
140    }
141    BaseCustom::<char>::new(chars)
142  }
143}
144
145impl PartialEq for BaseCustom<char> {
146  fn eq(&self, other: &BaseCustom<char>) -> bool {
147    self.primitives == other.primitives &&
148      self.base == other.base &&
149      self.delim == other.delim
150  }
151}
152
153impl fmt::Debug for BaseCustom<char> {
154  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
155    write!(f,
156      "BaseCustom\n\tprimitives: {:?}\n\tprimitives_hash: {:?}\n\tbase: {}\n\tdelim: {:?}",
157      self.primitives, self.primitives_hash, self.base, self.delim
158    )
159  }
160}