Package tripleplay.util

Source Code of tripleplay.util.TypedStorage

//
// Triple Play - utilities for use in PlayN-based games
// Copyright (c) 2011-2014, Three Rings Design, Inc. - All rights reserved.
// http://github.com/threerings/tripleplay/blob/master/LICENSE

package tripleplay.util;

import java.util.HashSet;
import java.util.Set;

import react.Function;
import react.IntValue;
import react.RSet;
import react.Slot;
import react.Value;

import playn.core.Storage;
import static playn.core.PlayN.log;

/**
* Makes using PlayN {@link Storage} more civilized. Provides getting and setting of typed values
* (ints, booleans, etc.). Provides support for default values. Provides {@link Value} interface to
* storage items.
*/
public class TypedStorage
{
    public TypedStorage (Storage storage) {
        _storage = storage;
    }

    /**
     * Returns whether the specified key is mapped to some value.
     */
    public boolean contains (String key) {
        return _storage.getItem(key) != null;
    }

    /**
     * Returns the specified property as a string, returning null if the property does not exist.
     */
    public String get (String key) {
        return _storage.getItem(key);
    }

    /**
     * Returns the specified property as a string, returning the supplied defautl value if the
     * property does not exist.
     */
    public String get (String key, String defval) {
        String value = _storage.getItem(key);
        return (value == null) ? defval : value;
    }

    /**
     * Sets the specified property to the supplied string value.
     */
    public void set (String key, String value) {
        _storage.setItem(key, value);
    }

    /**
     * Returns the specified property as an int. If the property does not exist, the default value
     * will be returned. If the property cannot be parsed as an int, an error will be logged and
     * the default value will be returned.
     */
    public int get (String key, int defval) {
        String value = null;
        try {
            value = _storage.getItem(key);
            return (value == null) ? defval : Integer.parseInt(value);
        } catch (Exception e) {
            log().warn("Failed to parse int prop [key=" + key + ", value=" + value + "]", e);
            return defval;
        }
    }

    /**
     * Sets the specified property to the supplied int value.
     */
    public void set (String key, int value) {
        _storage.setItem(key, String.valueOf(value));
    }

    /**
     * Returns the specified property as a long. If the property does not exist, the default value
     * will be returned. If the property cannot be parsed as a long, an error will be logged and
     * the default value will be returned.
     */
    public long get (String key, long defval) {
        String value = null;
        try {
            value = _storage.getItem(key);
            return (value == null) ? defval : Long.parseLong(value);
        } catch (Exception e) {
            log().warn("Failed to parse long prop [key=" + key + ", value=" + value + "]", e);
            return defval;
        }
    }

    /**
     * Sets the specified property to the supplied long value.
     */
    public void set (String key, long value) {
        _storage.setItem(key, String.valueOf(value));
    }

    /**
     * Returns the specified property as a double. If the property does not exist, the default
     * value will be returned. If the property cannot be parsed as a double, an error will be
     * logged and the default value will be returned.
     */
    public double get (String key, double defval) {
        String value = null;
        try {
            value = _storage.getItem(key);
            return (value == null) ? defval : Double.parseDouble(value);
        } catch (Exception e) {
            log().warn("Failed to parse double prop [key=" + key + ", value=" + value + "]", e);
            return defval;
        }
    }

    /**
     * Sets the specified property to the supplied double value.
     */
    public void set (String key, double value) {
        _storage.setItem(key, String.valueOf(value));
    }

    /**
     * Returns the specified property as a boolean. If the property does not exist, the default
     * value will be returned. Any existing value equal to {@code t} (ignoring case) will be
     * considered true; all others, false.
     */
    public boolean get (String key, boolean defval) {
        String value = _storage.getItem(key);
        return (value == null) ? defval : value.equalsIgnoreCase("t");
    }

    /**
     * Sets the specified property to the supplied boolean value.
     */
    public void set (String key, boolean value) {
        _storage.setItem(key, value ? "t" : "f");
    }

    /**
     * Returns the specified property as an enum. If the property does not exist, the default value
     * will be returned.
     * @throws NullPointerException if {@code defval} is null.
     */
    public <E extends Enum<E>> E get (String key, E defval) {
        @SuppressWarnings("unchecked") Class<E> eclass = (Class<E>)defval.getClass();
        String value = null;
        try {
            value = _storage.getItem(key);
            return (value == null) ? defval : Enum.valueOf(eclass, value);
        } catch (Exception e) {
            log().warn("Failed to parse enum prop [key=" + key + ", value=" + value + "]", e);
            return defval;
        }
    }

    /**
     * Sets the specified property to the supplied enum value.
     */
    public void set (String key, Enum<?> value) {
        _storage.setItem(key, value.name());
    }

    /**
     * Removes the specified key (and its value) from storage.
     */
    public void remove (String key) {
        _storage.removeItem(key);
    }

    /**
     * Exposes the specified property as a {@link Value}. The supplied default value will be used
     * if the property has no current value. Updates to the value will be written back to the
     * storage system. Note that each call to this method yields a new {@link Value} and those
     * values will not coordinate with one another, so the caller must be sure to only call this
     * method once for a given property and share that value properly.
     */
    public Value<String> valueFor (final String key, String defval) {
        Value<String> value = Value.create(get(key, defval));
        value.connect(new Slot<String>() {
            @Override public void onEmit (String value) {
                set(key, value);
            }
        });
        return value;
    }

    /**
     * Exposes the specified property as an {@link IntValue}. The supplied default value will be
     * used if the property has no current value. Updates to the value will be written back to the
     * storage system. Note that each call to this method yields a new {@link IntValue} and those
     * values will not coordinate with one another, so the caller must be sure to only call this
     * method once for a given property and share that value properly.
     */
    public IntValue valueFor (final String key, int defval) {
        IntValue value = new IntValue(get(key, defval));
        value.connect(new Slot<Integer>() {
            @Override public void onEmit (Integer value) {
                set(key, value);
            }
        });
        return value;
    }

    /**
     * Exposes the specified property as a {@link Value}. The supplied default value will be used
     * if the property has no current value. Updates to the value will be written back to the
     * storage system. Note that each call to this method yields a new {@link Value} and those
     * values will not coordinate with one another, so the caller must be sure to only call this
     * method once for a given property and share that value properly.
     */
    public Value<Long> valueFor (final String key, long defval) {
        Value<Long> value = Value.create(get(key, defval));
        value.connect(new Slot<Long>() {
            @Override public void onEmit (Long value) {
                set(key, value);
            }
        });
        return value;
    }

    /**
     * Exposes the specified property as a {@link Value}. The supplied default value will be used
     * if the property has no current value. Updates to the value will be written back to the
     * storage system. Note that each call to this method yields a new {@link Value} and those
     * values will not coordinate with one another, so the caller must be sure to only call this
     * method once for a given property and share that value properly.
     */
    public Value<Double> valueFor (final String key, double defval) {
        Value<Double> value = Value.create(get(key, defval));
        value.connect(new Slot<Double>() {
            @Override public void onEmit (Double value) {
                set(key, value);
            }
        });
        return value;
    }

    /**
     * Exposes the specified property as a {@link Value}. The supplied default value will be used
     * if the property has no current value. Updates to the value will be written back to the
     * storage system. Note that each call to this method yields a new {@link Value} and those
     * values will not coordinate with one another, so the caller must be sure to only call this
     * method once for a given property and share that value properly.
     */
    public Value<Boolean> valueFor (final String key, boolean defval) {
        Value<Boolean> value = Value.create(get(key, defval));
        value.connect(new Slot<Boolean>() {
            @Override public void onEmit (Boolean value) {
                set(key, value);
            }
        });
        return value;
    }

    /**
     * Exposes the specified property as a {@link Value}. The supplied default value will be used
     * if the property has no current value. Updates to the value will be written back to the
     * storage system. Note that each call to this method yields a new {@link Value} and those
     * values will not coordinate with one another, so the caller must be sure to only call this
     * method once for a given property and share that value properly.
     */
    public <E extends Enum<E>> Value<E> valueFor (final String key, E defval) {
        Value<E> value = Value.create(get(key, defval));
        value.connect(new Slot<E>() {
            @Override public void onEmit (E value) {
                set(key, value);
            }
        });
        return value;
    }

    /**
     * Exposes the specified property as an {@link RSet}. The contents of the set will be encoded
     * as a comma separated string and the supplied {@code toFunc} and {@code fromFunc} will be
     * used to convert an individual set item to and from a string. The to and from functions
     * should perform escaping and unescaping of commas if the encoded representation of the items
     * might naturally contain commas.
     *
     * <p>Any modifications to the set will be immediately persisted back to storage. Note that
     * each call to this method yields a new {@link RSet} and those sets will not coordinate with
     * one another, so the caller must be sure to only call this method once for a given property
     * and share that set properly. Changes to the underlying persistent value that do not take
     * place through the returned set will <em>not</em> be reflected in the set and will be
     * overwritten if the set changes.</p>
     */
    public <E> RSet<E> setFor (String key, Function<String,E> toFunc, Function<E,String> fromFunc) {
        return setFor(key, toFunc, fromFunc, new HashSet<E>());
    }

    /**
     * Exposes the specified property as an {@link RSet} using {@code impl} as the concrete set
     * implementation. See {@link #setFor(String,Function,Function)} for more details.
     */
    public <E> RSet<E> setFor (final String key, Function<String,E> toFunc,
                               final Function<E,String> fromFunc, Set<E> impl) {
        final RSet<E> rset = RSet.create(impl);
        String data = get(key, (String)null);
        if (data != null) {
            for (String value : data.split(",")) {
                try {
                    rset.add(toFunc.apply(value));
                } catch (Exception e) {
                    log().warn("Invalid value (key=" + key + "): " + value, e);
                }
            }
        }
        rset.connect(new RSet.Listener<E>() {
            @Override public void onAdd (E unused) { save(); }
            @Override public void onRemove (E unused) { save(); }
            protected void save () {
                if (rset.isEmpty()) remove(key);
                else {
                    StringBuilder buf = new StringBuilder();
                    int ii = 0;
                    for (E value : rset) {
                        if (ii++ > 0) buf.append(",");
                        buf.append(fromFunc.apply(value));
                    }
                    set(key, buf.toString());
                }
            }
        });
        return rset;
    }

    protected final Storage _storage;
}
TOP

Related Classes of tripleplay.util.TypedStorage

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.