Package org.codehaus.preon.codec

Source Code of org.codehaus.preon.codec.EnumCodec$Factory

/**
* Copyright (C) 2009-2010 Wilfred Springer
*
* This file is part of Preon.
*
* Preon is free software; you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2, or (at your option) any later version.
*
* Preon is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* Preon; see the file COPYING. If not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Linking this library statically or dynamically with other modules is making a
* combined work based on this library. Thus, the terms and conditions of the
* GNU General Public License cover the whole combination.
*
* As a special exception, the copyright holders of this library give you
* permission to link this library with independent modules to produce an
* executable, regardless of the license terms of these independent modules, and
* to copy and distribute the resulting executable under terms of your choice,
* provided that you also meet, for each linked independent module, the terms
* and conditions of the license of that module. An independent module is a
* module which is not derived from or based on this library. If you modify this
* library, you may extend this exception to your version of the library, but
* you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version.
*/
package org.codehaus.preon.codec;

import org.codehaus.preon.*;
import org.codehaus.preon.util.EnumUtils;
import org.codehaus.preon.annotation.BoundNumber;
import org.codehaus.preon.descriptor.Documenters;
import org.codehaus.preon.channel.BitChannel;
import org.codehaus.preon.buffer.ByteOrder;
import org.codehaus.preon.buffer.BitBuffer;
import org.codehaus.preon.el.Expression;
import org.codehaus.preon.el.Expressions;
import nl.flotsam.pecia.SimpleContents;
import nl.flotsam.pecia.Documenter;
import nl.flotsam.pecia.Para;
import nl.flotsam.pecia.ParaContents;

import java.util.Map;
import java.util.HashMap;
import java.io.IOException;
import java.lang.reflect.AnnotatedElement;

/**
* Created by IntelliJ IDEA. User: wilfred Date: Oct 24, 2009 Time: 5:03:58 PM To change this template use File |
* Settings | File Templates.
*/
public class EnumCodec<T> implements Codec<T> {

    private final Class<T> type;

    private final Map<Long, T> mapping;

    private final Map<T, Long> inverseMapping;

    private final Expression<Integer, Resolver> size;

    private final ByteOrder byteOrder;

    public EnumCodec(Class<T> type, Map<Long, T> mapping,
                     Expression<Integer, Resolver> sizeExpr, ByteOrder endian) {
        assert type != null;
        assert mapping != null;
        assert sizeExpr != null;
        assert endian != null;
        this.type = type;
        this.mapping = mapping;
        this.size = sizeExpr;
        this.byteOrder = endian;
        inverseMapping = new HashMap<T, Long>();
        for (Map.Entry<Long, T> entry : mapping.entrySet()) {
            inverseMapping.put(entry.getValue(), entry.getKey());
        }
    }

    public T decode(BitBuffer buffer, Resolver resolver, Builder builder)
            throws DecodingException {
        long value = buffer.readAsLong(size.eval(resolver), byteOrder);
        T result = mapping.get(value);
        if (result == null) {
            result = mapping.get(null);
        }
        return result;
    }

    public void encode(T object, BitChannel channel, Resolver resolver) throws IOException {
        channel.write(size.eval(resolver), inverseMapping.get(object), byteOrder);
    }

    public Class<?>[] getTypes() {
        return new Class[]{type};
    }

    public Expression<Integer, Resolver> getSize() {
        return size;
    }

    public Class<?> getType() {
        return type;
    }

    public CodecDescriptor getCodecDescriptor() {
        return new CodecDescriptor() {

            public <C extends SimpleContents<?>> Documenter<C> details(
                    String bufferReference) {
                return new Documenter<C>() {
                    public void document(C target) {
                        Para<?> para = target.para();
                        if (!size.isParameterized()) {
                            para.text("The symbol is represented as a ")
                                    .document(
                                            Documenters.forNumericValue(
                                                    size.eval(null),
                                                    byteOrder)).text(".");
                        } else {
                            para
                                    .text(
                                            "The symbol is represented as a numeric value (")
                                    .document(
                                            Documenters
                                                    .forByteOrder(byteOrder))
                                    .text(". The number of bits is ")
                                    .document(
                                            Documenters.forExpression(size))
                                    .text(".");
                        }
                        para
                                .text(
                                        " The numeric value corresponds to the following symbols:")
                                .end();
                        for (Map.Entry<Long, T> entry : mapping.entrySet()) {
                            if (entry.getKey() != null) {
                                target.para().text(
                                        Long.toString(entry.getKey()))
                                        .text(": ")
                                        .text(entry.getValue().toString())
                                        .end();
                            }
                        }
                        T defaultValue = mapping.get(null);
                        if (defaultValue != null) {
                            target.para().text("The default value is "
                                    + defaultValue.toString() + ".").end();
                        }
                    }
                };
            }

            public <C extends ParaContents<?>> Documenter<C> reference(
                    final Adjective adjective, boolean startWithCapital) {
                return new Documenter<C>() {
                    public void document(C target) {
                        target.text(adjective.asTextPreferAn(false)).text(
                                "index of an enumeration");
                    }
                };
            }

            public boolean requiresDedicatedSection() {
                return false;
            }

            public String getTitle() {
                return null;
            }

            public <C extends ParaContents<?>> Documenter<C> summary() {
                return new Documenter<C>() {
                    public void document(C target) {
                        target
                                .text("A value from a set of symbols, represented by a numeric value.");
                    }
                };
            }

        };
    }

    /**
     * A {@link org.codehaus.preon.CodecFactory} creating {@link org.codehaus.preon.Codec Codecs} capable of decoding enum
     * values. At this state, it will be triggered by enum type of fields with a {@link
     * org.codehaus.preon.annotation.BoundNumber} annotation, to pass metadata on the number of bits (and endianness) from
     * which the enum's value needs to get constructed.
     *
     * @author Wilfred Springer
     */
    public static class Factory implements CodecFactory {

        public <T> Codec<T> create(AnnotatedElement metadata, Class<T> type,
                                   ResolverContext context) {
            if (type.isEnum() && metadata.isAnnotationPresent(BoundNumber.class)) {
                Map<Long, T> mapping = EnumUtils.getBoundEnumOptionIndex(type);
                BoundNumber settings = metadata.getAnnotation(BoundNumber.class);
                Expression<Integer, Resolver> sizeExpr = Expressions.createInteger(
                        context, settings.size());
                return new EnumCodec<T>(type, mapping, sizeExpr, settings
                        .byteOrder());

            } else {
                return null;
            }
        }

    }
}
TOP

Related Classes of org.codehaus.preon.codec.EnumCodec$Factory

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.