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. */
010@SuppressWarnings({"UnnecessaryParentheses", "PMD.MethodReturnsInternalArray"})
011public final class NetworkTableValue {
012  NetworkTableValue(NetworkTableType type, Object value, long time, long serverTime) {
013    m_type = type;
014    m_value = value;
015    m_time = time;
016    m_serverTime = serverTime;
017  }
018
019  NetworkTableValue(NetworkTableType type, Object value, long time) {
020    this(type, value, time, time == 0 ? 0 : 1);
021  }
022
023  NetworkTableValue(NetworkTableType type, Object value) {
024    this(type, value, NetworkTablesJNI.now(), 1);
025  }
026
027  NetworkTableValue(int type, Object value, long time, long serverTime) {
028    this(NetworkTableType.getFromInt(type), value, time, serverTime);
029  }
030
031  /**
032   * Get the data type.
033   *
034   * @return The type.
035   */
036  public NetworkTableType getType() {
037    return m_type;
038  }
039
040  /**
041   * Get the data value stored.
042   *
043   * @return The type.
044   */
045  public Object getValue() {
046    return m_value;
047  }
048
049  /**
050   * Get the creation time of the value in local time.
051   *
052   * @return The time, in the units returned by NetworkTablesJNI.now().
053   */
054  public long getTime() {
055    return m_time;
056  }
057
058  /**
059   * Get the creation time of the value in server time.
060   *
061   * @return The server time.
062   */
063  public long getServerTime() {
064    return m_serverTime;
065  }
066
067  /*
068   * Type Checkers
069   */
070
071  /**
072   * Determine if entry value contains a value or is unassigned.
073   *
074   * @return True if the entry value contains a value.
075   */
076  public boolean isValid() {
077    return m_type != NetworkTableType.kUnassigned;
078  }
079
080  /**
081   * Determine if entry value contains a boolean.
082   *
083   * @return True if the entry value is of boolean type.
084   */
085  public boolean isBoolean() {
086    return m_type == NetworkTableType.kBoolean;
087  }
088
089  /**
090   * Determine if entry value contains a long.
091   *
092   * @return True if the entry value is of long type.
093   */
094  public boolean isInteger() {
095    return m_type == NetworkTableType.kInteger;
096  }
097
098  /**
099   * Determine if entry value contains a float.
100   *
101   * @return True if the entry value is of float type.
102   */
103  public boolean isFloat() {
104    return m_type == NetworkTableType.kFloat;
105  }
106
107  /**
108   * Determine if entry value contains a double.
109   *
110   * @return True if the entry value is of double type.
111   */
112  public boolean isDouble() {
113    return m_type == NetworkTableType.kDouble;
114  }
115
116  /**
117   * Determine if entry value contains a String.
118   *
119   * @return True if the entry value is of String type.
120   */
121  public boolean isString() {
122    return m_type == NetworkTableType.kString;
123  }
124
125  /**
126   * Determine if entry value contains a byte[].
127   *
128   * @return True if the entry value is of byte[] type.
129   */
130  public boolean isRaw() {
131    return m_type == NetworkTableType.kRaw;
132  }
133
134  /**
135   * Determine if entry value contains a boolean[].
136   *
137   * @return True if the entry value is of boolean[] type.
138   */
139  public boolean isBooleanArray() {
140    return m_type == NetworkTableType.kBooleanArray;
141  }
142
143  /**
144   * Determine if entry value contains a long[].
145   *
146   * @return True if the entry value is of long[] type.
147   */
148  public boolean isIntegerArray() {
149    return m_type == NetworkTableType.kIntegerArray;
150  }
151
152  /**
153   * Determine if entry value contains a float[].
154   *
155   * @return True if the entry value is of float[] type.
156   */
157  public boolean isFloatArray() {
158    return m_type == NetworkTableType.kFloatArray;
159  }
160
161  /**
162   * Determine if entry value contains a double[].
163   *
164   * @return True if the entry value is of double[] type.
165   */
166  public boolean isDoubleArray() {
167    return m_type == NetworkTableType.kDoubleArray;
168  }
169
170  /**
171   * Determine if entry value contains a String[].
172   *
173   * @return True if the entry value is of String[] type.
174   */
175  public boolean isStringArray() {
176    return m_type == NetworkTableType.kStringArray;
177  }
178
179  /*
180   * Type-Safe Getters
181   */
182
183  /**
184   * Get the boolean value.
185   *
186   * @return The boolean value.
187   * @throws ClassCastException if the entry value is not of boolean type.
188   */
189  public boolean getBoolean() {
190    if (m_type != NetworkTableType.kBoolean) {
191      throw new ClassCastException("cannot convert " + m_type + " to boolean");
192    }
193    return (Boolean) m_value;
194  }
195
196  /**
197   * Get the long value.
198   *
199   * @return The long value.
200   * @throws ClassCastException if the entry value is not of long type.
201   */
202  public long getInteger() {
203    if (m_type != NetworkTableType.kInteger) {
204      throw new ClassCastException("cannot convert " + m_type + " to long");
205    }
206    return ((Number) m_value).longValue();
207  }
208
209  /**
210   * Get the float value.
211   *
212   * @return The float value.
213   * @throws ClassCastException if the entry value is not of float type.
214   */
215  public float getFloat() {
216    if (m_type != NetworkTableType.kFloat) {
217      throw new ClassCastException("cannot convert " + m_type + " to float");
218    }
219    return ((Number) m_value).floatValue();
220  }
221
222  /**
223   * Get the double value.
224   *
225   * @return The double value.
226   * @throws ClassCastException if the entry value is not of double type.
227   */
228  public double getDouble() {
229    if (m_type != NetworkTableType.kDouble) {
230      throw new ClassCastException("cannot convert " + m_type + " to double");
231    }
232    return ((Number) m_value).doubleValue();
233  }
234
235  /**
236   * Get the String value.
237   *
238   * @return The String value.
239   * @throws ClassCastException if the entry value is not of String type.
240   */
241  public String getString() {
242    if (m_type != NetworkTableType.kString) {
243      throw new ClassCastException("cannot convert " + m_type + " to String");
244    }
245    return (String) m_value;
246  }
247
248  /**
249   * Get the byte[] value.
250   *
251   * @return The byte[] value.
252   * @throws ClassCastException if the entry value is not of byte[] type.
253   */
254  public byte[] getRaw() {
255    if (m_type != NetworkTableType.kRaw) {
256      throw new ClassCastException("cannot convert " + m_type + " to byte[]");
257    }
258    return (byte[]) m_value;
259  }
260
261  /**
262   * Get the boolean[] value.
263   *
264   * @return The boolean[] value.
265   * @throws ClassCastException if the entry value is not of boolean[] type.
266   */
267  public boolean[] getBooleanArray() {
268    if (m_type != NetworkTableType.kBooleanArray) {
269      throw new ClassCastException("cannot convert " + m_type + " to boolean[]");
270    }
271    return (boolean[]) m_value;
272  }
273
274  /**
275   * Get the long[] value.
276   *
277   * @return The long[] value.
278   * @throws ClassCastException if the entry value is not of long[] type.
279   */
280  public long[] getIntegerArray() {
281    if (m_type != NetworkTableType.kIntegerArray) {
282      throw new ClassCastException("cannot convert " + m_type + " to long[]");
283    }
284    return (long[]) m_value;
285  }
286
287  /**
288   * Get the float[] value.
289   *
290   * @return The float[] value.
291   * @throws ClassCastException if the entry value is not of float[] type.
292   */
293  public float[] getFloatArray() {
294    if (m_type != NetworkTableType.kFloatArray) {
295      throw new ClassCastException("cannot convert " + m_type + " to float[]");
296    }
297    return (float[]) m_value;
298  }
299
300  /**
301   * Get the double[] value.
302   *
303   * @return The double[] value.
304   * @throws ClassCastException if the entry value is not of double[] type.
305   */
306  public double[] getDoubleArray() {
307    if (m_type != NetworkTableType.kDoubleArray) {
308      throw new ClassCastException("cannot convert " + m_type + " to double[]");
309    }
310    return (double[]) m_value;
311  }
312
313  /**
314   * Get the String[] value.
315   *
316   * @return The String[] value.
317   * @throws ClassCastException if the entry value is not of String[] type.
318   */
319  public String[] getStringArray() {
320    if (m_type != NetworkTableType.kStringArray) {
321      throw new ClassCastException("cannot convert " + m_type + " to String[]");
322    }
323    return (String[]) m_value;
324  }
325
326  /*
327   * Factory functions.
328   */
329
330  /**
331   * Creates a boolean value.
332   *
333   * @param value the value
334   * @return The entry value
335   */
336  public static NetworkTableValue makeBoolean(boolean value) {
337    return new NetworkTableValue(NetworkTableType.kBoolean, Boolean.valueOf(value));
338  }
339
340  /**
341   * Creates a boolean value.
342   *
343   * @param value the value
344   * @param time the creation time to use (instead of the current time)
345   * @return The entry value
346   */
347  public static NetworkTableValue makeBoolean(boolean value, long time) {
348    return new NetworkTableValue(NetworkTableType.kBoolean, Boolean.valueOf(value), time);
349  }
350
351  /**
352   * Creates a long value.
353   *
354   * @param value the value
355   * @return The entry value
356   */
357  public static NetworkTableValue makeInteger(long value) {
358    return new NetworkTableValue(NetworkTableType.kInteger, Long.valueOf(value));
359  }
360
361  /**
362   * Creates a long value.
363   *
364   * @param value the value
365   * @param time the creation time to use (instead of the current time)
366   * @return The entry value
367   */
368  public static NetworkTableValue makeInteger(long value, long time) {
369    return new NetworkTableValue(NetworkTableType.kInteger, Long.valueOf(value), time);
370  }
371
372  /**
373   * Creates a float value.
374   *
375   * @param value the value
376   * @return The entry value
377   */
378  public static NetworkTableValue makeFloat(float value) {
379    return new NetworkTableValue(NetworkTableType.kFloat, Float.valueOf(value));
380  }
381
382  /**
383   * Creates a float value.
384   *
385   * @param value the value
386   * @param time the creation time to use (instead of the current time)
387   * @return The entry value
388   */
389  public static NetworkTableValue makeFloat(float value, long time) {
390    return new NetworkTableValue(NetworkTableType.kFloat, Float.valueOf(value), time);
391  }
392
393  /**
394   * Creates a double value.
395   *
396   * @param value the value
397   * @return The entry value
398   */
399  public static NetworkTableValue makeDouble(double value) {
400    return new NetworkTableValue(NetworkTableType.kDouble, Double.valueOf(value));
401  }
402
403  /**
404   * Creates a double value.
405   *
406   * @param value the value
407   * @param time the creation time to use (instead of the current time)
408   * @return The entry value
409   */
410  public static NetworkTableValue makeDouble(double value, long time) {
411    return new NetworkTableValue(NetworkTableType.kDouble, Double.valueOf(value), time);
412  }
413
414  /**
415   * Creates a String value.
416   *
417   * @param value the value
418   * @return The entry value
419   */
420  public static NetworkTableValue makeString(String value) {
421    return new NetworkTableValue(NetworkTableType.kString, (value));
422  }
423
424  /**
425   * Creates a String value.
426   *
427   * @param value the value
428   * @param time the creation time to use (instead of the current time)
429   * @return The entry value
430   */
431  public static NetworkTableValue makeString(String value, long time) {
432    return new NetworkTableValue(NetworkTableType.kString, (value), time);
433  }
434
435  /**
436   * Creates a byte[] value.
437   *
438   * @param value the value
439   * @return The entry value
440   */
441  public static NetworkTableValue makeRaw(byte[] value) {
442    return new NetworkTableValue(NetworkTableType.kRaw, (value));
443  }
444
445  /**
446   * Creates a byte[] value.
447   *
448   * @param value the value
449   * @param time the creation time to use (instead of the current time)
450   * @return The entry value
451   */
452  public static NetworkTableValue makeRaw(byte[] value, long time) {
453    return new NetworkTableValue(NetworkTableType.kRaw, (value), time);
454  }
455
456  /**
457   * Creates a boolean[] value.
458   *
459   * @param value the value
460   * @return The entry value
461   */
462  public static NetworkTableValue makeBooleanArray(boolean[] value) {
463    return new NetworkTableValue(NetworkTableType.kBooleanArray, (value));
464  }
465
466  /**
467   * Creates a boolean[] value.
468   *
469   * @param value the value
470   * @param time the creation time to use (instead of the current time)
471   * @return The entry value
472   */
473  public static NetworkTableValue makeBooleanArray(boolean[] value, long time) {
474    return new NetworkTableValue(NetworkTableType.kBooleanArray, (value), time);
475  }
476
477  /**
478   * Creates a boolean[] value.
479   *
480   * @param value the value
481   * @return The entry value
482   */
483  public static NetworkTableValue makeBooleanArray(Boolean[] value) {
484    return new NetworkTableValue(NetworkTableType.kBooleanArray, toNativeBooleanArray(value));
485  }
486
487  /**
488   * Creates a boolean[] value.
489   *
490   * @param value the value
491   * @param time the creation time to use (instead of the current time)
492   * @return The entry value
493   */
494  public static NetworkTableValue makeBooleanArray(Boolean[] value, long time) {
495    return new NetworkTableValue(NetworkTableType.kBooleanArray, toNativeBooleanArray(value), time);
496  }
497
498  /**
499   * Creates a long[] value.
500   *
501   * @param value the value
502   * @return The entry value
503   */
504  public static NetworkTableValue makeIntegerArray(long[] value) {
505    return new NetworkTableValue(NetworkTableType.kIntegerArray, (value));
506  }
507
508  /**
509   * Creates a long[] value.
510   *
511   * @param value the value
512   * @param time the creation time to use (instead of the current time)
513   * @return The entry value
514   */
515  public static NetworkTableValue makeIntegerArray(long[] value, long time) {
516    return new NetworkTableValue(NetworkTableType.kIntegerArray, (value), time);
517  }
518
519  /**
520   * Creates a long[] value.
521   *
522   * @param value the value
523   * @return The entry value
524   */
525  public static NetworkTableValue makeIntegerArray(Long[] value) {
526    return new NetworkTableValue(NetworkTableType.kIntegerArray, toNativeIntegerArray(value));
527  }
528
529  /**
530   * Creates a long[] value.
531   *
532   * @param value the value
533   * @param time the creation time to use (instead of the current time)
534   * @return The entry value
535   */
536  public static NetworkTableValue makeIntegerArray(Long[] value, long time) {
537    return new NetworkTableValue(NetworkTableType.kIntegerArray, toNativeIntegerArray(value), time);
538  }
539
540  /**
541   * Creates a float[] value.
542   *
543   * @param value the value
544   * @return The entry value
545   */
546  public static NetworkTableValue makeFloatArray(float[] value) {
547    return new NetworkTableValue(NetworkTableType.kFloatArray, (value));
548  }
549
550  /**
551   * Creates a float[] value.
552   *
553   * @param value the value
554   * @param time the creation time to use (instead of the current time)
555   * @return The entry value
556   */
557  public static NetworkTableValue makeFloatArray(float[] value, long time) {
558    return new NetworkTableValue(NetworkTableType.kFloatArray, (value), time);
559  }
560
561  /**
562   * Creates a float[] value.
563   *
564   * @param value the value
565   * @return The entry value
566   */
567  public static NetworkTableValue makeFloatArray(Float[] value) {
568    return new NetworkTableValue(NetworkTableType.kFloatArray, toNativeFloatArray(value));
569  }
570
571  /**
572   * Creates a float[] value.
573   *
574   * @param value the value
575   * @param time the creation time to use (instead of the current time)
576   * @return The entry value
577   */
578  public static NetworkTableValue makeFloatArray(Float[] value, long time) {
579    return new NetworkTableValue(NetworkTableType.kFloatArray, toNativeFloatArray(value), time);
580  }
581
582  /**
583   * Creates a double[] value.
584   *
585   * @param value the value
586   * @return The entry value
587   */
588  public static NetworkTableValue makeDoubleArray(double[] value) {
589    return new NetworkTableValue(NetworkTableType.kDoubleArray, (value));
590  }
591
592  /**
593   * Creates a double[] value.
594   *
595   * @param value the value
596   * @param time the creation time to use (instead of the current time)
597   * @return The entry value
598   */
599  public static NetworkTableValue makeDoubleArray(double[] value, long time) {
600    return new NetworkTableValue(NetworkTableType.kDoubleArray, (value), time);
601  }
602
603  /**
604   * Creates a double[] value.
605   *
606   * @param value the value
607   * @return The entry value
608   */
609  public static NetworkTableValue makeDoubleArray(Double[] value) {
610    return new NetworkTableValue(NetworkTableType.kDoubleArray, toNativeDoubleArray(value));
611  }
612
613  /**
614   * Creates a double[] value.
615   *
616   * @param value the value
617   * @param time the creation time to use (instead of the current time)
618   * @return The entry value
619   */
620  public static NetworkTableValue makeDoubleArray(Double[] value, long time) {
621    return new NetworkTableValue(NetworkTableType.kDoubleArray, toNativeDoubleArray(value), time);
622  }
623
624  /**
625   * Creates a String[] value.
626   *
627   * @param value the value
628   * @return The entry value
629   */
630  public static NetworkTableValue makeStringArray(String[] value) {
631    return new NetworkTableValue(NetworkTableType.kStringArray, (value));
632  }
633
634  /**
635   * Creates a String[] value.
636   *
637   * @param value the value
638   * @param time the creation time to use (instead of the current time)
639   * @return The entry value
640   */
641  public static NetworkTableValue makeStringArray(String[] value, long time) {
642    return new NetworkTableValue(NetworkTableType.kStringArray, (value), time);
643  }
644
645  @Override
646  public boolean equals(Object other) {
647    if (other == this) {
648      return true;
649    }
650    if (!(other instanceof NetworkTableValue)) {
651      return false;
652    }
653    NetworkTableValue ntOther = (NetworkTableValue) other;
654    return m_type == ntOther.m_type && m_value.equals(ntOther.m_value);
655  }
656
657  @Override
658  public int hashCode() {
659    return Objects.hash(m_type, m_value);
660  }
661
662  // arraycopy() doesn't know how to unwrap boxed values; this is a false positive in PMD
663  // (see https://sourceforge.net/p/pmd/bugs/804/)
664  @SuppressWarnings("PMD.AvoidArrayLoops")
665  static boolean[] toNativeBooleanArray(Boolean[] arr) {
666    boolean[] out = new boolean[arr.length];
667    for (int i = 0; i < arr.length; i++) {
668      out[i] = arr[i];
669    }
670    return out;
671  }
672
673  @SuppressWarnings("PMD.AvoidArrayLoops")
674  static double[] toNativeDoubleArray(Number[] arr) {
675    double[] out = new double[arr.length];
676    for (int i = 0; i < arr.length; i++) {
677      out[i] = arr[i].doubleValue();
678    }
679    return out;
680  }
681
682  @SuppressWarnings("PMD.AvoidArrayLoops")
683  static long[] toNativeIntegerArray(Number[] arr) {
684    long[] out = new long[arr.length];
685    for (int i = 0; i < arr.length; i++) {
686      out[i] = arr[i].longValue();
687    }
688    return out;
689  }
690
691  @SuppressWarnings("PMD.AvoidArrayLoops")
692  static float[] toNativeFloatArray(Number[] arr) {
693    float[] out = new float[arr.length];
694    for (int i = 0; i < arr.length; i++) {
695      out[i] = arr[i].floatValue();
696    }
697    return out;
698  }
699
700  @SuppressWarnings("PMD.AvoidArrayLoops")
701  static Boolean[] fromNativeBooleanArray(boolean[] arr) {
702    Boolean[] out = new Boolean[arr.length];
703    for (int i = 0; i < arr.length; i++) {
704      out[i] = arr[i];
705    }
706    return out;
707  }
708
709  @SuppressWarnings("PMD.AvoidArrayLoops")
710  static Long[] fromNativeIntegerArray(long[] arr) {
711    Long[] out = new Long[arr.length];
712    for (int i = 0; i < arr.length; i++) {
713      out[i] = arr[i];
714    }
715    return out;
716  }
717
718  @SuppressWarnings("PMD.AvoidArrayLoops")
719  static Float[] fromNativeFloatArray(float[] arr) {
720    Float[] out = new Float[arr.length];
721    for (int i = 0; i < arr.length; i++) {
722      out[i] = arr[i];
723    }
724    return out;
725  }
726
727  @SuppressWarnings("PMD.AvoidArrayLoops")
728  static Double[] fromNativeDoubleArray(double[] arr) {
729    Double[] out = new Double[arr.length];
730    for (int i = 0; i < arr.length; i++) {
731      out[i] = arr[i];
732    }
733    return out;
734  }
735
736  private NetworkTableType m_type;
737  private Object m_value;
738  private long m_time;
739  private long m_serverTime;
740}