diff --git a/epilogue-runtime/src/main/java/edu/wpi/first/epilogue/logging/LazyBackend.java b/epilogue-runtime/src/main/java/edu/wpi/first/epilogue/logging/LazyBackend.java index 7a04cffbde..adad963e07 100644 --- a/epilogue-runtime/src/main/java/edu/wpi/first/epilogue/logging/LazyBackend.java +++ b/epilogue-runtime/src/main/java/edu/wpi/first/epilogue/logging/LazyBackend.java @@ -117,7 +117,7 @@ public class LazyBackend implements EpilogueBackend { return; } - m_previousValues.put(identifier, value); + m_previousValues.put(identifier, value.clone()); m_backend.log(identifier, value); } @@ -130,7 +130,7 @@ public class LazyBackend implements EpilogueBackend { return; } - m_previousValues.put(identifier, value); + m_previousValues.put(identifier, value.clone()); m_backend.log(identifier, value); } @@ -143,7 +143,7 @@ public class LazyBackend implements EpilogueBackend { return; } - m_previousValues.put(identifier, value); + m_previousValues.put(identifier, value.clone()); m_backend.log(identifier, value); } @@ -156,7 +156,7 @@ public class LazyBackend implements EpilogueBackend { return; } - m_previousValues.put(identifier, value); + m_previousValues.put(identifier, value.clone()); m_backend.log(identifier, value); } @@ -169,7 +169,7 @@ public class LazyBackend implements EpilogueBackend { return; } - m_previousValues.put(identifier, value); + m_previousValues.put(identifier, value.clone()); m_backend.log(identifier, value); } @@ -182,7 +182,7 @@ public class LazyBackend implements EpilogueBackend { return; } - m_previousValues.put(identifier, value); + m_previousValues.put(identifier, value.clone()); m_backend.log(identifier, value); } @@ -208,7 +208,7 @@ public class LazyBackend implements EpilogueBackend { return; } - m_previousValues.put(identifier, value); + m_previousValues.put(identifier, value.clone()); m_backend.log(identifier, value); } @@ -234,7 +234,7 @@ public class LazyBackend implements EpilogueBackend { return; } - m_previousValues.put(identifier, value); + m_previousValues.put(identifier, value.clone()); m_backend.log(identifier, value, struct); } } diff --git a/epilogue-runtime/src/test/java/edu/wpi/first/epilogue/logging/CustomStruct.java b/epilogue-runtime/src/test/java/edu/wpi/first/epilogue/logging/CustomStruct.java new file mode 100644 index 0000000000..d79ae2bc16 --- /dev/null +++ b/epilogue-runtime/src/test/java/edu/wpi/first/epilogue/logging/CustomStruct.java @@ -0,0 +1,45 @@ +// Copyright (c) FIRST and other WPILib contributors. +// Open Source Software; you can modify and/or share it under the terms of +// the WPILib BSD license file in the root directory of this project. + +package edu.wpi.first.epilogue.logging; + +import edu.wpi.first.util.struct.Struct; +import edu.wpi.first.util.struct.StructSerializable; +import java.nio.ByteBuffer; + +public record CustomStruct(int x) implements StructSerializable { + public static final Serializer struct = new Serializer(); + + public static final class Serializer implements Struct { + @Override + public Class getTypeClass() { + return CustomStruct.class; + } + + @Override + public String getTypeName() { + return "CustomStruct"; + } + + @Override + public int getSize() { + return kSizeInt32; + } + + @Override + public String getSchema() { + return "int32 x;"; + } + + @Override + public CustomStruct unpack(ByteBuffer bb) { + return new CustomStruct(bb.getInt()); + } + + @Override + public void pack(ByteBuffer bb, CustomStruct value) { + bb.putInt(value.x); + } + } +} diff --git a/epilogue-runtime/src/test/java/edu/wpi/first/epilogue/logging/LazyBackendTest.java b/epilogue-runtime/src/test/java/edu/wpi/first/epilogue/logging/LazyBackendTest.java index 104cb0f380..d0b394330c 100644 --- a/epilogue-runtime/src/test/java/edu/wpi/first/epilogue/logging/LazyBackendTest.java +++ b/epilogue-runtime/src/test/java/edu/wpi/first/epilogue/logging/LazyBackendTest.java @@ -4,6 +4,7 @@ package edu.wpi.first.epilogue.logging; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertSame; @@ -53,4 +54,135 @@ class LazyBackendTest { backend.getEntries()); } } + + @Test + void inPlaceByteArray() { + var backend = new TestBackend(); + var lazy = new LazyBackend(backend); + + byte[] arr = new byte[] {0}; + lazy.log("arr", arr); + + arr[0] = 1; + lazy.log("arr", arr); + + assertEquals(2, backend.getEntries().size()); + assertArrayEquals(new byte[] {0}, (byte[]) backend.getEntries().get(0).value()); + assertArrayEquals(new byte[] {1}, (byte[]) backend.getEntries().get(1).value()); + } + + @Test + void inPlaceIntArray() { + var backend = new TestBackend(); + var lazy = new LazyBackend(backend); + + int[] arr = new int[] {0}; + lazy.log("arr", arr); + + arr[0] = 1; + lazy.log("arr", arr); + + assertEquals(2, backend.getEntries().size()); + assertArrayEquals(new int[] {0}, (int[]) backend.getEntries().get(0).value()); + assertArrayEquals(new int[] {1}, (int[]) backend.getEntries().get(1).value()); + } + + @Test + void inPlaceLongArray() { + var backend = new TestBackend(); + var lazy = new LazyBackend(backend); + + long[] arr = new long[] {0}; + lazy.log("arr", arr); + + arr[0] = 1; + lazy.log("arr", arr); + + assertEquals(2, backend.getEntries().size()); + assertArrayEquals(new long[] {0}, (long[]) backend.getEntries().get(0).value()); + assertArrayEquals(new long[] {1}, (long[]) backend.getEntries().get(1).value()); + } + + @Test + void inPlaceFloatArray() { + var backend = new TestBackend(); + var lazy = new LazyBackend(backend); + + float[] arr = new float[] {0}; + lazy.log("arr", arr); + + arr[0] = 1; + lazy.log("arr", arr); + + assertEquals(2, backend.getEntries().size()); + assertArrayEquals(new float[] {0}, (float[]) backend.getEntries().get(0).value()); + assertArrayEquals(new float[] {1}, (float[]) backend.getEntries().get(1).value()); + } + + @Test + void inPlaceDoubleArray() { + var backend = new TestBackend(); + var lazy = new LazyBackend(backend); + + double[] arr = new double[] {0}; + lazy.log("arr", arr); + + arr[0] = 1; + lazy.log("arr", arr); + + assertEquals(2, backend.getEntries().size()); + assertArrayEquals(new double[] {0}, (double[]) backend.getEntries().get(0).value()); + assertArrayEquals(new double[] {1}, (double[]) backend.getEntries().get(1).value()); + } + + @Test + void inPlaceBooleanArray() { + var backend = new TestBackend(); + var lazy = new LazyBackend(backend); + + boolean[] arr = new boolean[] {false}; + lazy.log("arr", arr); + + arr[0] = true; + lazy.log("arr", arr); + + assertEquals(2, backend.getEntries().size()); + assertArrayEquals(new boolean[] {false}, (boolean[]) backend.getEntries().get(0).value()); + assertArrayEquals(new boolean[] {true}, (boolean[]) backend.getEntries().get(1).value()); + } + + @Test + void inPlaceStringArray() { + var backend = new TestBackend(); + var lazy = new LazyBackend(backend); + + String[] arr = new String[] {"0"}; + lazy.log("arr", arr); + + arr[0] = "1"; + lazy.log("arr", arr); + + assertEquals(2, backend.getEntries().size()); + assertArrayEquals(new String[] {"0"}, (String[]) backend.getEntries().get(0).value()); + assertArrayEquals(new String[] {"1"}, (String[]) backend.getEntries().get(1).value()); + } + + @Test + void inPlaceStructArray() { + var backend = new TestBackend(); + var lazy = new LazyBackend(backend); + + CustomStruct[] arr = new CustomStruct[] {new CustomStruct(0)}; + + lazy.log("arr", arr, CustomStruct.struct); + + arr[0] = new CustomStruct(1); + lazy.log("arr", arr, CustomStruct.struct); + + assertEquals(2, backend.getEntries().size()); + assertArrayEquals( + new byte[] {0x00, 0x00, 0x00, 0x00}, (byte[]) backend.getEntries().get(0).value()); + assertArrayEquals( + new byte[] {0x01, 0x00, 0x00, 0x00}, (byte[]) backend.getEntries().get(1).value()); + } } diff --git a/epilogue-runtime/src/test/java/edu/wpi/first/epilogue/logging/TestBackend.java b/epilogue-runtime/src/test/java/edu/wpi/first/epilogue/logging/TestBackend.java index e2b88a1066..1372921002 100644 --- a/epilogue-runtime/src/test/java/edu/wpi/first/epilogue/logging/TestBackend.java +++ b/epilogue-runtime/src/test/java/edu/wpi/first/epilogue/logging/TestBackend.java @@ -55,32 +55,32 @@ public class TestBackend implements EpilogueBackend { @Override public void log(String identifier, byte[] value) { - m_entries.add(new LogEntry<>(identifier, value)); + m_entries.add(new LogEntry<>(identifier, value.clone())); } @Override public void log(String identifier, int[] value) { - m_entries.add(new LogEntry<>(identifier, value)); + m_entries.add(new LogEntry<>(identifier, value.clone())); } @Override public void log(String identifier, long[] value) { - m_entries.add(new LogEntry<>(identifier, value)); + m_entries.add(new LogEntry<>(identifier, value.clone())); } @Override public void log(String identifier, float[] value) { - m_entries.add(new LogEntry<>(identifier, value)); + m_entries.add(new LogEntry<>(identifier, value.clone())); } @Override public void log(String identifier, double[] value) { - m_entries.add(new LogEntry<>(identifier, value)); + m_entries.add(new LogEntry<>(identifier, value.clone())); } @Override public void log(String identifier, boolean[] value) { - m_entries.add(new LogEntry<>(identifier, value)); + m_entries.add(new LogEntry<>(identifier, value.clone())); } @Override @@ -90,19 +90,27 @@ public class TestBackend implements EpilogueBackend { @Override public void log(String identifier, String[] value) { - m_entries.add(new LogEntry<>(identifier, value)); + m_entries.add(new LogEntry<>(identifier, value.clone())); } @Override public void log(String identifier, S value, Struct struct) { - var serialized = StructBuffer.create(struct).write(value).array(); + var buffer = StructBuffer.create(struct).write(value).position(0); + var serialized = new byte[buffer.capacity()]; + for (int i = 0; i < buffer.capacity(); i++) { + serialized[i] = buffer.get(); + } m_entries.add(new LogEntry<>(identifier, serialized)); } @Override public void log(String identifier, S[] value, Struct struct) { - var serialized = StructBuffer.create(struct).writeArray(value).array(); + var buffer = StructBuffer.create(struct).writeArray(value).position(0); + var serialized = new byte[buffer.capacity()]; + for (int i = 0; i < buffer.capacity(); i++) { + serialized[i] = buffer.get(); + } m_entries.add(new LogEntry<>(identifier, serialized)); }