/*
* Copyright (c) 2012-2014, Parallel Universe Software Co. All rights reserved.
*
* This program and the accompanying materials are dual-licensed under
* either the terms of the Eclipse Public License v1.0 as published by
* the Eclipse Foundation
*
* or (per the licensee's choosing)
*
* under the terms of the GNU Lesser General Public License version 3.0
* as published by the Free Software Foundation.
*/
package co.paralleluniverse.common.io;
import java.io.IOException;
import java.nio.ByteBuffer;
/**
* Provides utility methods for working with {@link Persistable}s and/or {@link ByteBuffer}s.
*
* @author pron
*/
public final class Persistables {
/**
* Converts a {@link Streamable} into a {@link Persistable}.
*
* @param streamable A {@link Streamable} object.
* @return A {@link Persistable} representation of the given object.
*/
public static Persistable persistable(final Streamable streamable) {
return new Persistable() {
@Override
public int size() {
return streamable.size();
}
@Override
public void write(ByteBuffer buffer) {
try {
streamable.write(new ByteBufferOutputStream(buffer));
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
@Override
public void read(ByteBuffer buffer) {
try {
streamable.read(new ByteBufferInputStream(buffer));
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
};
}
/**
* Converts a {@link ByteBuffer} into a {@link Persistable}.
*
* @param buffer The buffer
* @return A Persistable wrapper for the buffer.
*/
public static Persistable persistable(final ByteBuffer buffer) {
return new Persistable() {
@Override
public int size() {
return buffer.limit();
}
@Override
public void write(ByteBuffer buffer1) {
buffer1.put(buffer);
buffer1.flip();
}
@Override
public void read(ByteBuffer buffer1) {
buffer.rewind();
buffer.put(buffer1);
buffer.rewind();
}
};
}
/**
* Returns an array containing a {@link ByteBuffer}'s {@link ByteBuffer#remaining() remaining} contents. <br> Upon returning
* from this method, the buffer's {@link ByteBuffer#position() position} will remain unchanged.
*
* @param buffer The buffer to write into the array.
* @return A newly allocated array of size {@link ByteBuffer#remaining() buffer.remaining()} containing the buffer's contents.
*/
public static byte[] toByteArray(ByteBuffer buffer) {
if (buffer.hasArray() && buffer.arrayOffset() == 0
&& buffer.position() == 0 && buffer.limit() == buffer.capacity()
&& buffer.array().length == buffer.capacity()) {
final byte[] array = buffer.array();
return array;
}
final int p = buffer.position();
final byte[] array = new byte[buffer.remaining()];
buffer.get(array);
buffer.position(p);
return array;
}
/**
* Returns a newly-allocated copy of a given {@link ByteBuffer}'s {@link ByteBuffer#remaining() remaining} contents. <br>
* Upon return from this method, the original buffer's {@link ByteBuffer#position() position} will be unchanged, and the
* returned buffer's position will be 0.
* <p>
* This method is not thread-safe.
*
* @param buffer The buffer to copy.
* @return A copy of the buffer's {@link ByteBuffer#remaining() remaining} contents.
*/
public static ByteBuffer copyOf(ByteBuffer buffer) {
final int n = buffer.capacity();
final ByteBuffer buffer2 = ByteBuffer.allocate(n);
final int p = buffer.position();
buffer.position(0);
final int l = buffer.limit();
buffer.limit(n);
buffer2.put(buffer);
buffer2.flip();
buffer.position(p);
buffer.limit(l);
return buffer2;
}
/**
* Returns a newly allocated {@link ByteBuffer#slice()} of a given {@link ByteBuffer}. The slice and the original buffer will
* share their contents. <br> Upon return from this method, the original buffer's {@link ByteBuffer#position() position} will
* be unchanged, and the returned buffer's position will be 0.
* <p>
* This method is not thread-safe.
*
* @param buffer The buffer to slice.
* @param start The position of the slice's start in the given buffer.
* @param length The length in bytes of the slice.
* @return A slice of the buffer.
* @see ByteBuffer#slice()
*/
public static ByteBuffer slice(ByteBuffer buffer, int start, int length) {
final int l = buffer.limit();
final int p = buffer.position();
buffer.limit(start + length);
buffer.position(start);
final ByteBuffer slice = buffer.slice();
buffer.limit(l);
buffer.position(p);
return slice;
}
/**
* Returns a newly allocated {@link ByteBuffer#slice()}, starting from the current {@link ByteBuffer#position() position}, of
* a given {@link ByteBuffer}. The slice and the original buffer will share their contents. <br> Upon return from this
* method, the original buffer's {@link ByteBuffer#position() position} will have advanced by {@code length}, and the returned
* buffer's position will be 0.
* <p>
* This method is not thread-safe.
*
* @param buffer The buffer to slice.
* @param length The length in bytes of the slice.
* @return A slice of the buffer.
* @see ByteBuffer#slice()
*/
public static ByteBuffer slice(ByteBuffer buffer, int length) {
final int l = buffer.limit();
buffer.limit(buffer.position() + length);
final ByteBuffer slice = buffer.slice();
buffer.limit(l);
buffer.position(buffer.position() + length);
return slice;
}
private Persistables() {
}
}