001// Copyright (c) FIRST and other WPILib contributors.
002// Open Source Software; you can modify and/or share it under the terms of
003// the WPILib BSD license file in the root directory of this project.
004
005package edu.wpi.first.networktables;
006
007import java.util.Objects;
008
009/** A network table entry value. */
010public final class NetworkTableValue {
011  NetworkTableValue(NetworkTableType type, Object value, long time) {
012    m_type = type;
013    m_value = value;
014    m_time = time;
015  }
016
017  NetworkTableValue(NetworkTableType type, Object value) {
018    this(type, value, NetworkTablesJNI.now());
019  }
020
021  NetworkTableValue(int type, Object value, long time) {
022    this(NetworkTableType.getFromInt(type), value, time);
023  }
024
025  /**
026   * Get the data type.
027   *
028   * @return The type.
029   */
030  public NetworkTableType getType() {
031    return m_type;
032  }
033
034  /**
035   * Get the data value stored.
036   *
037   * @return The type.
038   */
039  public Object getValue() {
040    return m_value;
041  }
042
043  /**
044   * Get the creation time of the value.
045   *
046   * @return The time, in the units returned by NetworkTablesJNI.now().
047   */
048  public long getTime() {
049    return m_time;
050  }
051
052  /*
053   * Type Checkers
054   */
055
056  /**
057   * Determine if entry value contains a value or is unassigned.
058   *
059   * @return True if the entry value contains a value.
060   */
061  public boolean isValid() {
062    return m_type != NetworkTableType.kUnassigned;
063  }
064
065  /**
066   * Determine if entry value contains a boolean.
067   *
068   * @return True if the entry value is of boolean type.
069   */
070  public boolean isBoolean() {
071    return m_type == NetworkTableType.kBoolean;
072  }
073
074  /**
075   * Determine if entry value contains a double.
076   *
077   * @return True if the entry value is of double type.
078   */
079  public boolean isDouble() {
080    return m_type == NetworkTableType.kDouble;
081  }
082
083  /**
084   * Determine if entry value contains a string.
085   *
086   * @return True if the entry value is of string type.
087   */
088  public boolean isString() {
089    return m_type == NetworkTableType.kString;
090  }
091
092  /**
093   * Determine if entry value contains a raw.
094   *
095   * @return True if the entry value is of raw type.
096   */
097  public boolean isRaw() {
098    return m_type == NetworkTableType.kRaw;
099  }
100
101  /**
102   * Determine if entry value contains a rpc definition.
103   *
104   * @return True if the entry value is of rpc definition type.
105   */
106  public boolean isRpc() {
107    return m_type == NetworkTableType.kRpc;
108  }
109
110  /**
111   * Determine if entry value contains a boolean array.
112   *
113   * @return True if the entry value is of boolean array type.
114   */
115  public boolean isBooleanArray() {
116    return m_type == NetworkTableType.kBooleanArray;
117  }
118
119  /**
120   * Determine if entry value contains a double array.
121   *
122   * @return True if the entry value is of double array type.
123   */
124  public boolean isDoubleArray() {
125    return m_type == NetworkTableType.kDoubleArray;
126  }
127
128  /**
129   * Determine if entry value contains a string array.
130   *
131   * @return True if the entry value is of string array type.
132   */
133  public boolean isStringArray() {
134    return m_type == NetworkTableType.kStringArray;
135  }
136
137  /*
138   * Type-Safe Getters
139   */
140
141  /**
142   * Get the entry's boolean value.
143   *
144   * @return The boolean value.
145   * @throws ClassCastException if the entry value is not of boolean type.
146   */
147  public boolean getBoolean() {
148    if (m_type != NetworkTableType.kBoolean) {
149      throw new ClassCastException("cannot convert " + m_type + " to boolean");
150    }
151    return (Boolean) m_value;
152  }
153
154  /**
155   * Get the entry's double value.
156   *
157   * @return The double value.
158   * @throws ClassCastException if the entry value is not of double type.
159   */
160  public double getDouble() {
161    if (m_type != NetworkTableType.kDouble) {
162      throw new ClassCastException("cannot convert " + m_type + " to double");
163    }
164    return ((Number) m_value).doubleValue();
165  }
166
167  /**
168   * Get the entry's string value.
169   *
170   * @return The string value.
171   * @throws ClassCastException if the entry value is not of string type.
172   */
173  public String getString() {
174    if (m_type != NetworkTableType.kString) {
175      throw new ClassCastException("cannot convert " + m_type + " to string");
176    }
177    return (String) m_value;
178  }
179
180  /**
181   * Get the entry's raw value.
182   *
183   * @return The raw value.
184   * @throws ClassCastException if the entry value is not of raw type.
185   */
186  @SuppressWarnings("PMD.MethodReturnsInternalArray")
187  public byte[] getRaw() {
188    if (m_type != NetworkTableType.kRaw) {
189      throw new ClassCastException("cannot convert " + m_type + " to raw");
190    }
191    return (byte[]) m_value;
192  }
193
194  /**
195   * Get the entry's rpc definition value.
196   *
197   * @return The rpc definition value.
198   * @throws ClassCastException if the entry value is not of rpc definition type.
199   */
200  @SuppressWarnings("PMD.MethodReturnsInternalArray")
201  public byte[] getRpc() {
202    if (m_type != NetworkTableType.kRpc) {
203      throw new ClassCastException("cannot convert " + m_type + " to rpc");
204    }
205    return (byte[]) m_value;
206  }
207
208  /**
209   * Get the entry's boolean array value.
210   *
211   * @return The boolean array value.
212   * @throws ClassCastException if the entry value is not of boolean array type.
213   */
214  @SuppressWarnings("PMD.MethodReturnsInternalArray")
215  public boolean[] getBooleanArray() {
216    if (m_type != NetworkTableType.kBooleanArray) {
217      throw new ClassCastException("cannot convert " + m_type + " to boolean array");
218    }
219    return (boolean[]) m_value;
220  }
221
222  /**
223   * Get the entry's double array value.
224   *
225   * @return The double array value.
226   * @throws ClassCastException if the entry value is not of double array type.
227   */
228  @SuppressWarnings("PMD.MethodReturnsInternalArray")
229  public double[] getDoubleArray() {
230    if (m_type != NetworkTableType.kDoubleArray) {
231      throw new ClassCastException("cannot convert " + m_type + " to double array");
232    }
233    return (double[]) m_value;
234  }
235
236  /**
237   * Get the entry's string array value.
238   *
239   * @return The string array value.
240   * @throws ClassCastException if the entry value is not of string array type.
241   */
242  @SuppressWarnings("PMD.MethodReturnsInternalArray")
243  public String[] getStringArray() {
244    if (m_type != NetworkTableType.kStringArray) {
245      throw new ClassCastException("cannot convert " + m_type + " to string array");
246    }
247    return (String[]) m_value;
248  }
249
250  /*
251   * Factory functions.
252   */
253
254  /**
255   * Creates a boolean entry value.
256   *
257   * @param value the value
258   * @return The entry value
259   */
260  public static NetworkTableValue makeBoolean(boolean value) {
261    return new NetworkTableValue(NetworkTableType.kBoolean, Boolean.valueOf(value));
262  }
263
264  /**
265   * Creates a boolean entry value.
266   *
267   * @param value the value
268   * @param time the creation time to use (instead of the current time)
269   * @return The entry value
270   */
271  public static NetworkTableValue makeBoolean(boolean value, long time) {
272    return new NetworkTableValue(NetworkTableType.kBoolean, Boolean.valueOf(value), time);
273  }
274
275  /**
276   * Creates a double entry value.
277   *
278   * @param value the value
279   * @return The entry value
280   */
281  public static NetworkTableValue makeDouble(double value) {
282    return new NetworkTableValue(NetworkTableType.kDouble, Double.valueOf(value));
283  }
284
285  /**
286   * Creates a double entry value.
287   *
288   * @param value the value
289   * @param time the creation time to use (instead of the current time)
290   * @return The entry value
291   */
292  public static NetworkTableValue makeDouble(double value, long time) {
293    return new NetworkTableValue(NetworkTableType.kDouble, Double.valueOf(value), time);
294  }
295
296  /**
297   * Creates a string entry value.
298   *
299   * @param value the value
300   * @return The entry value
301   */
302  public static NetworkTableValue makeString(String value) {
303    return new NetworkTableValue(NetworkTableType.kString, value);
304  }
305
306  /**
307   * Creates a string entry value.
308   *
309   * @param value the value
310   * @param time the creation time to use (instead of the current time)
311   * @return The entry value
312   */
313  public static NetworkTableValue makeString(String value, long time) {
314    return new NetworkTableValue(NetworkTableType.kString, value, time);
315  }
316
317  /**
318   * Creates a raw entry value.
319   *
320   * @param value the value
321   * @return The entry value
322   */
323  public static NetworkTableValue makeRaw(byte[] value) {
324    return new NetworkTableValue(NetworkTableType.kRaw, value);
325  }
326
327  /**
328   * Creates a raw entry value.
329   *
330   * @param value the value
331   * @param time the creation time to use (instead of the current time)
332   * @return The entry value
333   */
334  public static NetworkTableValue makeRaw(byte[] value, long time) {
335    return new NetworkTableValue(NetworkTableType.kRaw, value, time);
336  }
337
338  /**
339   * Creates a rpc entry value.
340   *
341   * @param value the value
342   * @return The entry value
343   */
344  public static NetworkTableValue makeRpc(byte[] value) {
345    return new NetworkTableValue(NetworkTableType.kRpc, value);
346  }
347
348  /**
349   * Creates a rpc entry value.
350   *
351   * @param value the value
352   * @param time the creation time to use (instead of the current time)
353   * @return The entry value
354   */
355  public static NetworkTableValue makeRpc(byte[] value, long time) {
356    return new NetworkTableValue(NetworkTableType.kRpc, value, time);
357  }
358
359  /**
360   * Creates a boolean array entry value.
361   *
362   * @param value the value
363   * @return The entry value
364   */
365  public static NetworkTableValue makeBooleanArray(boolean[] value) {
366    return new NetworkTableValue(NetworkTableType.kBooleanArray, value);
367  }
368
369  /**
370   * Creates a boolean array entry value.
371   *
372   * @param value the value
373   * @param time the creation time to use (instead of the current time)
374   * @return The entry value
375   */
376  public static NetworkTableValue makeBooleanArray(boolean[] value, long time) {
377    return new NetworkTableValue(NetworkTableType.kBooleanArray, value, time);
378  }
379
380  /**
381   * Creates a boolean array entry value.
382   *
383   * @param value the value
384   * @return The entry value
385   */
386  public static NetworkTableValue makeBooleanArray(Boolean[] value) {
387    return new NetworkTableValue(NetworkTableType.kBooleanArray, toNative(value));
388  }
389
390  /**
391   * Creates a boolean array entry value.
392   *
393   * @param value the value
394   * @param time the creation time to use (instead of the current time)
395   * @return The entry value
396   */
397  public static NetworkTableValue makeBooleanArray(Boolean[] value, long time) {
398    return new NetworkTableValue(NetworkTableType.kBooleanArray, toNative(value), time);
399  }
400
401  /**
402   * Creates a double array entry value.
403   *
404   * @param value the value
405   * @return The entry value
406   */
407  public static NetworkTableValue makeDoubleArray(double[] value) {
408    return new NetworkTableValue(NetworkTableType.kDoubleArray, value);
409  }
410
411  /**
412   * Creates a double array entry value.
413   *
414   * @param value the value
415   * @param time the creation time to use (instead of the current time)
416   * @return The entry value
417   */
418  public static NetworkTableValue makeDoubleArray(double[] value, long time) {
419    return new NetworkTableValue(NetworkTableType.kDoubleArray, value, time);
420  }
421
422  /**
423   * Creates a double array entry value.
424   *
425   * @param value the value
426   * @return The entry value
427   */
428  public static NetworkTableValue makeDoubleArray(Number[] value) {
429    return new NetworkTableValue(NetworkTableType.kDoubleArray, toNative(value));
430  }
431
432  /**
433   * Creates a double array entry value.
434   *
435   * @param value the value
436   * @param time the creation time to use (instead of the current time)
437   * @return The entry value
438   */
439  public static NetworkTableValue makeDoubleArray(Number[] value, long time) {
440    return new NetworkTableValue(NetworkTableType.kDoubleArray, toNative(value), time);
441  }
442
443  /**
444   * Creates a string array entry value.
445   *
446   * @param value the value
447   * @return The entry value
448   */
449  public static NetworkTableValue makeStringArray(String[] value) {
450    return new NetworkTableValue(NetworkTableType.kStringArray, value);
451  }
452
453  /**
454   * Creates a string array entry value.
455   *
456   * @param value the value
457   * @param time the creation time to use (instead of the current time)
458   * @return The entry value
459   */
460  public static NetworkTableValue makeStringArray(String[] value, long time) {
461    return new NetworkTableValue(NetworkTableType.kStringArray, value, time);
462  }
463
464  @Override
465  public boolean equals(Object other) {
466    if (other == this) {
467      return true;
468    }
469    if (!(other instanceof NetworkTableValue)) {
470      return false;
471    }
472    NetworkTableValue ntOther = (NetworkTableValue) other;
473    return m_type == ntOther.m_type && m_value.equals(ntOther.m_value);
474  }
475
476  @Override
477  public int hashCode() {
478    return Objects.hash(m_type, m_value);
479  }
480
481  // arraycopy() doesn't know how to unwrap boxed values; this is a false positive in PMD
482  // (see https://sourceforge.net/p/pmd/bugs/804/)
483  @SuppressWarnings("PMD.AvoidArrayLoops")
484  static boolean[] toNative(Boolean[] arr) {
485    boolean[] out = new boolean[arr.length];
486    for (int i = 0; i < arr.length; i++) {
487      out[i] = arr[i];
488    }
489    return out;
490  }
491
492  @SuppressWarnings("PMD.AvoidArrayLoops")
493  static double[] toNative(Number[] arr) {
494    double[] out = new double[arr.length];
495    for (int i = 0; i < arr.length; i++) {
496      out[i] = arr[i].doubleValue();
497    }
498    return out;
499  }
500
501  @SuppressWarnings("PMD.AvoidArrayLoops")
502  static Boolean[] fromNative(boolean[] arr) {
503    Boolean[] out = new Boolean[arr.length];
504    for (int i = 0; i < arr.length; i++) {
505      out[i] = arr[i];
506    }
507    return out;
508  }
509
510  @SuppressWarnings("PMD.AvoidArrayLoops")
511  static Double[] fromNative(double[] arr) {
512    Double[] out = new Double[arr.length];
513    for (int i = 0; i < arr.length; i++) {
514      out[i] = arr[i];
515    }
516    return out;
517  }
518
519  private NetworkTableType m_type;
520  private Object m_value;
521  private long m_time;
522}