PPI: Checkin of first compiling (yet not working) version
[senf.git] / Packets / PacketParser.hh
index cd45e47..2b73860 100644 (file)
@@ -1,7 +1,7 @@
 // Copyright (C) 2007 
 // Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
 // Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
-//     Stefan Bund <g0dil@berlios.de>
+//     Stefan Bund <g0dil@berlios.be>
 //
 // This program is free software; you can redistribute it and/or modify
 // it under the terms of the GNU General Public License as published by
 /** \defgroup packetparser The PacketParser facility
     
     The PacketParser facility provides a framework to implement very lightweight classes which parse
-    the raw content of a packet into meaningful values. PacketParsers are always passed around by
-    value, they can be understood as pointers into the data structure with added type information
-    providing parsing functions.
-
-    Parsers are built hirarchically. A high-level parser will return other parsers when returning
-    some element (Example: Asking an EthernetParser for the ethertype field by calling the parsers
-    \c type() member will return an UInt16 parser). The lowest level building blocks then return the
+    the raw content of a packet into meaningful values. PacketParsers are always passed around
+    <em>by value</em>, they can be understood as pointers into the packet data with added type
+    information providing parsing functions.
+
+    Packet parsers are \e only used within the packet framework. You should never allocate a new
+    parser instance directly, you should the Packet library let that do for you (either by having
+    the parser as a packet parser in a packet type or by having a member in the packet parser which
+    allocates the parser as a sub-parser).
+
+    Parsers are built hierarchically. A high-level parser will return other parsers when accessing
+    an element (Example: Asking an EthernetParser for the ethertype field by calling the parsers \c
+    type() member will return an \c UInt16 parser). The lowest level building blocks then return the
     values. This hierarchical structure greatly simplifies building complex parsers.
 
-    Every parser is derived from senf::PacketParserBase. This parser provides the necessary
-    housekeeping information and provides the parsers with access to the data.
+    Since parsers are very lightweight and are passed by value, packet fields are accessed using the
+    corresponding accessor method:
+    \code
+      SomePacket p (...)
+      SomePacket q (...)
+
+      // Assign new value to an integer parser
+      p->someField() = 10;
+
+      // Write out above value
+      std::cerr << p->someField() << "\n";
+
+      // Use the generic parser-assignment operator '<<' to copy field values
+      p->someVector()[1].someOtherField() << q->someField();
+      p->someVector() << q->someVector()
+    \endcode
+
+    Here \c someField(), \c someOtherField() and \c someVector() are accessor methods named after
+    the field name. Each returns a parser object. Simple parsers can be used like their
+    corresponding basic type (e.g. a Parse_UInt16 field can be used like an unsigned integer), more
+    complex parsers provide type specific access members. Assigning a value to a parser will change
+    the underlying representation (the packet data). 
+
+    Parsers can be grouped into several categories. These categories are not all defined rigorously
+    but are nevertheless helpful when working with the parsers:
+    \li <em>Value parsers</em> provide the lowest level parsers (e.g. senf::Parse_UInt16 which
+        returns an integer value).
+    \li <em>Collection parsers</em> are parsers which model a collection of sub-elements like
+        senf::Parse_List or senf::Parse_Vector.
+    \li <em>Composite parsers</em> collect several fields of arbitrary type into a new
+        parser. Parsers defined using the \ref packetparsermacros fall under this category.
+    \li <em>Packet parsers</em> are used to define a packet type.
+
+    \warning Parsers are like iterators: They are invalidated <em>whenever the size of the packet's
+    data is changed</em>. You should not store a parser anywhere. If you want to keep a parser
+    reference, use the senf::SafePacketParser wrapper. You still will need to take extra care to
+    ensure the parser is not invalidated.
+
+    \section parserimpl Packet parser categories
+
+    Every parser is derived from senf::PacketParserBase. This class provides the necessary
+    housekeeping information and provides the parsers with access to the data. You may in principle
+    define arbitrary methods as parser members (e.g. methods to calculate a checksum, methods
+    processing fields in some way and so on). You should however be very wary to access data outside
+    the range assigned to the packet (the range starting at \c i() and with a size of senf::bytes()
+    bytes).
+    
+    Each parser type has specific features
+
+    \subsection parserimpl_value Value parsers
+
+    For a parser \a SomeParser to be a value parser, the following expressions must be valid:
+    \code
+    // SomeParser must have a 'value_type', The 'value_type' must be default constructible, copy
+    // constructible and assignable
+    SomeParser::value_type v; 
+
+    // An instance of 'SomeParser' must have a 'value' member which returns a value which may be
+    // assigned to a variable of type 'value_type'
+    v = p.someParserField().value()
+
+    // It must be possible to assign a new value using the 'value' member
+    p.someParserField().value(v)
+    \endcode
+
+    If at all possible, the 'value_type' should not reference the packet data using iterators or
+    pointers, it should hold a copy of the value (it's Ok for \c value() to return such a reference
+    as long as assigning it to a \c value_type variable will copy the value).
+
+    \subsection parserimpl_collection Collection parsers
+
+    A collection parser \a SomeParser should model STL containers. The parsers themselves will
+    probably only // provide a reduced interface, but the collection parser should have a \c
+    collection member which is a wrapper providing the full interface.
+    \code
+    SomeParser::container c (p.someParserField());
+    \endcode
 
-    The PacketParser facility predefines several parsers to be used as building blocks in defining
-    more complex parsers (integer parsers, several parsers for repetitive constructs)
+    You will probably only very seldom need to implement a completely new collection
+    parser. Instead, you can rely on senf::Parse_Vector or senf::Parse_List and implement new
+    polcies.
+
+    \subsection parserimpl_composite Composite parsers
+    
+    If possible, composite parsers should be implemented using the \ref packetparsermacros. In
+    addition to the normal parser requirements, these macros ensure, that for each field,
+    <em>fieldname</em><tt>_t</tt> is a typedef for the fields parser and
+    <em>fieldname</em><tt>_offset</tt> is the offset of the field in bytes from the beginning of the
+    parser (either a constant for fixed size parsers or a member function for dynamically sized
+    parsers). When defining composite parsers without the help of the \ref packetparsermacros, you
+    should provide those same members.
+
+    \subsection parserimpl_packet Packet parsers
+
+    Packet parsers are composite parsers with relaxed requirements. Since a packet parser will never
+    be used as a sub-parser (it will not be used within another composite parser or as value type in
+    a collection parser), the value returned by senf::bytes for this parser must not necessarily
+    cover the complete packet (e.g. if the packet has a trailer, the trailer will live outside the
+    range given by senf::bytes). You may define any member you want to have in your packets field
+    interface. These members may access the packet data in any way. You just need to ensure, that
+    the integration into the packet-type is correct (the senf::PacketTypeMixin will by default use
+    senf::bytes() to find the end of the header).
+    
  */
 
 #ifndef HH_PacketParser_
 #include <boost/optional.hpp>
 #include "Utils/SafeBool.hh"
 #include "PacketTypes.hh"
-#define HH_PacketData_DeclOnly
 #include "PacketData.hh"
-#undef HH_PacketData_DeclOnly
 
 #include "PacketParser.mpp"
 ///////////////////////////////hh.p////////////////////////////////////////
 
 namespace senf {
     
-    /** \brief Parser Baseclass
+    /** \brief Parser Base class
+
+        Parsers come in two flavors: fixed and dynamically sized parsers. A <em>fixed size
+        parser</em> has a constant size, it will always parse a fixed number of bytes. The low-level
+        'final'  parsers (like the integer parsers) are fixed size parsers as are composite parsers
+        built up only of fixed-size fields.
 
-        To implement a packet parser, you need to derive from PacketParserBase and implement several
-        required members. There are two ways how to do this.
-        \li If the parser just consists of a simple sequence of consecutive fields, the
-            SENF_PACKET_PARESR_DEFINE_FIELDS and SENF_PACKET_PARSER_DEFINE_FIXED_FIELDS macros
-            provide a simple an convenient way to define the packet
+        A <em>dynamically sized</em> parser on the other hand infers it's size from the contents of
+        the data parsed. Any parser containing at least one dynamically sized sub-parser will itself
+        be dynamically sized.
+        
+        Both kinds of parser need to derive from PacketParserBase and implement several required
+        members. Which members to implement depends on the parsers flavor. There are two ways how to
+        do this.
+        \li If the parser just consists of a simple sequence of consecutive fields (sub-parsers),
+            the \ref SENF_PACKET_PARSER_DEFINE_FIELDS and \ref
+            SENF_PACKET_PARSER_DEFINE_FIXED_FIELDS macros provide a simple and convenient way to
+            define the packet
         \li In more complex cases, you need to implement the necessary members manually.
 
-        The following example documents the interface (which must be) provided by a parser.
+        This documentation is about the manual implementation. You should nevertheless read through
+        this to understand, what above macros are doing.
+
+        The following example documents the interface (which must be) provided by a parser:
         \code
           struct FooParser : public PacketParserBase
           {
@@ -85,7 +200,7 @@ namespace senf {
               // of bytes to allocate when creating a new object
               static const size_type init_bytes = some_constant_size;
 
-              // You also mey define an init() member. This will be called to initialize a newly
+              // You also may define an init() member. This will be called to initialize a newly
               // created data object. The default implementation just does nothing.
               void init() const;
 
@@ -101,13 +216,13 @@ namespace senf {
         \endcode
         
         You should never call the \c bytes() member of a parser directly. Instead you should use the
-        freestanding senf::bytes() functon. This function will return the correct size even for
-        fixed-size parsers. You may access \c fixed_bytes directly, however be aware that this will
-        restrict your code to fixed size parsers (which depending on the circumstances may be
+        freestanding senf::bytes() function. This function will return the correct size irrespective
+        of the parsers flavor. You may access \c fixed_bytes directly, however be aware that this
+        will restrict your code to fixed size parsers (which depending on the circumstances may be
         exactly what you want).
 
-        In the same way, dont access \c init_bytes directly, always use the senf::init_bytes
-        metafunction class which will correctly support fixed size parsers.
+        In the same way, don't access \c init_bytes directly, always use the senf::init_bytes
+        meta-function class which correctly supports fixed size parsers.
 
         \ingroup packetparser
       */
@@ -117,11 +232,11 @@ namespace senf {
         ///////////////////////////////////////////////////////////////////////////
         // Types
 
-        typedef detail::packet::iterator data_iterator;
-        typedef detail::packet::size_type size_type;
-        typedef detail::packet::difference_type difference_type;
-        typedef detail::packet::byte byte;
-        typedef PacketData * state_type;
+        typedef detail::packet::iterator data_iterator; ///< Raw data iterator type
+        typedef detail::packet::size_type size_type; ///< Unsigned integral type
+        typedef detail::packet::difference_type difference_type; ///< Signed integral type
+        typedef detail::packet::byte byte; ///< Unsigned 8bit value, the raw value type
+        typedef PacketData * state_type; ///< Type of the 'state' parameter
 
         ///////////////////////////////////////////////////////////////////////////
         ///\name Structors and default members
@@ -135,23 +250,68 @@ namespace senf {
         ///@}
         ///////////////////////////////////////////////////////////////////////////
 
-        data_iterator i() const;
-        state_type state() const;
-        PacketData & data() const;
-
-        void init() const;
+        data_iterator i() const;        ///< Return beginning of data to parse
+                                        /**< The parser is expected to interpret the data beginning
+                                             here. The size of the interpreted is given by
+                                             <tt>senf::bytes(</tt><em>parser
+                                             instance</em><tt>)</tt>. */
+        state_type state() const;       ///< Return state of this parser
+                                        /**< The value returned should be interpreted as an opaque
+                                             value provided just to be forwarded to other
+                                             parsers. */
+        PacketData & data() const;      ///< Access the packets raw data container
+                                        /**< This member will return the raw data container holding
+                                             the data which is parsed by \c this parser. */
+
+        void init() const;              ///< Default implementation
+                                        /**< This is just an empty default
+                                             implementation. Re-implement this member in your own
+                                             parsers if needed. */
 
     protected:
-        PacketParserBase(data_iterator i, state_type s);
-        PacketParserBase(data_iterator i, state_type s, size_type size);
-
-        bool check(size_type size);
-        void validate(size_type size);
-
-        template <class Parser> Parser parse(data_iterator i) const;
-        template <class Parser> Parser parse(size_type n) const;
-
-        void defaultInit() const;
+        PacketParserBase(data_iterator i, state_type s); ///< Standard constructor
+                                        /**< This is the constructor used by most parsers. The
+                                             parameters are just forwarded from the derived classes
+                                             constructor parameters. */
+        PacketParserBase(data_iterator i, state_type s, size_type size); 
+                                        ///< Size checking constructor
+                                        /**< In addition to the standard constructor, this
+                                             constructor will validate, that there is enough data in
+                                             the raw data container to parse \a size bytes after \a
+                                             i.
+
+                                             This constructor is called by all 'final' parsers
+                                             (e.g. the integer parsers) and \e only by those
+                                             parsers. Most parsers do \e not check the validity of
+                                             the iterator, this is delayed until the very last
+                                             parser. This allows to partial parse truncated
+                                             packets.
+
+                                             \throw TruncatedPacketException if the raw data
+                                                 container does not hold at least \a size bytes
+                                                 beginning at \a i. */
+
+        bool check(size_type size);     ///< Check size of data container
+                                        /**< \returns \c true, if the data container holds at least
+                                             \a size beginning at i(), \c false otherwise. */
+        void validate(size_type size);  ///< Validate size of data container
+                                        /**< \throws TruncatedPacketException if the raw data
+                                             container does not hold at least \a size bytes
+                                             beginning at i(). */
+
+        template <class Parser> Parser parse(data_iterator i) const; ///< Create sub-parser
+                                        /**< Creates a new instance of \a Parser to parse data
+                                             beginning at \a i. Automatically passes \a state() to
+                                             the new parser. */
+        template <class Parser> Parser parse(size_type n) const; ///< Create sub-parser
+                                        /**< Creates a new instance of \a Parser to parse data
+                                         * beginning at i()<tt> + </tt>\a n. Automatically passes \a
+                                             state() to the new parser. */
+
+        void defaultInit() const;       ///< Default implementation
+                                        /**< This is just an empty default
+                                             implementation. Re-implement this member in your own
+                                             parsers if needed. */
 
     private:
         data_iterator end();
@@ -183,16 +343,16 @@ namespace senf {
 
     /** \brief Return number of bytes to allocate to new object of given type
 
-        This metafcuntion is called like
+        This meta-function is called like
         \code
             senf::init_bytes<SomeParser>::value
         \endcode
 
-        This expression evaluates to a compile-time constant itegral expression of type
-        senf::PacketParserBase::size_type. This metafunction will return \c Parser::fixed_bytes or
+        This expression evaluates to a compile-time constant integral expression of type
+        senf::PacketParserBase::size_type. This meta-function will return \c Parser::fixed_bytes or
         \c Parser::init_bytes depending on the type of parser.
 
-        \param[in] Parser Parser to return init_bytes for
+        \param[in] Parser The Parser to return init_bytes for
         \returns Number of bytes to allocate to the new object
         \ingroup packetparser
      */
@@ -200,49 +360,77 @@ namespace senf {
     struct init_bytes : public detail::ParserInitBytes<Parser>
     {};
 
+#   ifndef DOXYGEN
     template <class Parser>
     typename boost::enable_if< 
         boost::is_base_of<PacketParserBase, Parser>,
         Parser >::type
     operator<<(Parser target, Parser source);
+#   else
+    /** \brief Generic parser copying
+
+        This operator allows to copy the values of identical parsers. This operation does \e not
+        depend on the parsers detailed implementation, it will just replace the data bytes of the
+        target parser with those from the source parser. This allows to easily copy around complex
+        packet substructures.
 
+        This operation is different from the ordinary assignment operator: It does not change the \a
+        target parser, it changes the data referenced by the \a target parser.
+
+        \ingroup packetparser
+     */
+    template <class Parser>
+    Parser operator<<(Parser target, Parser source);
+#   endif
+
+#   ifndef DOXYGEN
     template <class Parser, class Value>
     typename boost::enable_if_c < 
         boost::is_base_of<PacketParserBase, Parser>::value 
             && ! boost::is_base_of<PacketParserBase, Value>::value,
         Parser >::type
     operator<<(Parser target, Value const & value);
+#   else 
+    /** \brief Generic parser value assignment
+
+        This operator allows to assign a value to parsers which implement a <tt>value(</tt>\a
+        value<tt>)</tt> member. This operator allows to use a common syntax for assigning values or
+        parsers to a parser. 
+
+        \ingroup packetparser
+     */
+    template <class Parser, class Value>
+    Parser operator<<(Parser target, Value const & value);
+#   endif
 
     /** \defgroup packetparsermacros Helper macros for defining new packet parsers
         
         To simplify the definition of simple packet parsers, several macros are provided. Before
-        using these macros you should familarize yourself with the packet parser interface as
+        using these macros you should familiarize yourself with the packet parser interface as
         described in senf::PacketParserBase.
 
         These macros simplify providing the above defined interface. A typical packet declaration
         using these macros has the following form (This is a concrete example from the definition of
-        the ethernet packet in <tt>DefaultBundle//EthernetPacket.hh</tt>)
+        the ethernet packet in <tt>DefaultBundle/EthernetPacket.hh</tt>)
+    
         \code
-            struct Parse_EthVLan : public senf::PacketParserBase
-            {
-                SENF_PACKET_PARSER_INIT(Parse_EthVLan);
-
-                // ////////////////////////////////////////////////////////////////////////
-
-                typedef senf::Parse_UIntField < 0,  3 > Parse_Priority;
-                typedef senf::Parse_Flag          < 3 > Parse_CFI;
-                typedef senf::Parse_UIntField < 4, 16 > Parse_VLanId;
-                typedef senf::Parse_UInt16              Parse_Type;
-
-                SENF_PACKET_PARSER_DEFINE_FIXED_FIELDS(
-                    ((OverlayField)( priority, Parse_Priority ))
-                    ((OverlayField)( cfi,      Parse_CFI      ))
-                    ((Field       )( vlanId,   Parse_VLanId   ))
-                    ((Field       )( type,     Parse_Type     )) 
-                );
-            };
+        struct Parse_EthVLan : public PacketParserBase
+        {
+            typedef Parse_UIntField < 0,  3 > Parse_Priority;
+            typedef Parse_Flag          < 3 > Parse_CFI;
+            typedef Parse_UIntField < 4, 16 > Parse_VLanId;
+            typedef Parse_UInt16              Parse_Type;
+
+            SENF_PACKET_PARSER_INIT(Parse_EthVLan);
+
+            SENF_PACKET_PARSER_DEFINE_FIXED_FIELDS(
+                ((OverlayField)( priority, Parse_Priority ))
+                ((OverlayField)( cfi,      Parse_CFI      ))
+                ((Field       )( vlanId,   Parse_VLanId   ))
+                ((Field       )( type,     Parse_Type     )) );
+        };
         \endcode
-
+        
         The macros take care of the following:
         \li They define the accessor functions returning parsers of the given type.
         \li They automatically calculate the offset of the fields from the preceding fields.
@@ -273,6 +461,13 @@ namespace senf {
           )
         \endcode
         
+        For each field, this command will define
+        \li A method \a name() returning an instance of the \a type parser
+        \li \a name<tt>_t</tt> as a typedef for \a type, the fields value
+        \li \a name<tt>_offset</tt> to give the offset of the field from the beginning of the
+            parser. If the parser is a fixed size parser, this will be a static constant, otherwise
+            it will be a method.
+
         The \a builder argument selects, how the field is defined
         \li <tt>Field</tt> defines a field and increments the current position by the size of the
             field
@@ -284,10 +479,10 @@ namespace senf {
         The \a name argument defines the name of the accessor method.
 
         The \a type argument is the parser to return for that field. Since none of the arguments may
-        contain a komma, <em>This argument cannot be a template</em>. Always use typedefs to access
-        tempalte parsers as shown above.
+        contain a comma, <em>This argument cannot be a multi-parameter template</em>. Always use
+        typedefs to access templated parsers as shown above.
 
-        The \ref SENF_PACKET_PARSER_INIT makro defines the constructor and the \c init() member. If
+        The \ref SENF_PACKET_PARSER_INIT macro defines the constructor and the \c init() member. If
         you want to provide your own \c init() implementation, use \ref
         SENF_PACKET_PARSER_NO_INIT. The first statement in your init method should probably to call
         \c defaultInit(). This will call the \c init() member of all the fields. Afterwards you can
@@ -331,7 +526,7 @@ namespace senf {
     name(data_iterator i, state_type s) : senf::PacketParserBase(i,s) {}                          \
     void init() const { defaultInit(); }
 
-    /** \brief Define initialization mebers of a parser except init()
+    /** \brief Define initialization members of a parser except init()
         
         This macro is like SENF_PACKET_PARSER_INIT but does \e not define \c init(). This allows you
         to provide your own implementation. You should call \c defaultInit() first before
@@ -352,8 +547,37 @@ namespace senf {
         \hideinitializer
      */
 #   define SENF_PACKET_PARSER_DEFINE_FIELDS(fields)                                               \
-    SENF_PACKET_PARSER_I_DEFINE_FIELDS(fields)
+    SENF_PACKET_PARSER_I_DEFINE_FIELDS(0,fields)
         
+    /** \brief Define fields for a dynamically sized parser (with offset)
+
+        Define the fields as specified in \a fields. This macro supports dynamically sized
+        subfields, the resulting parser will be dynamically sized.
+
+        The \a offset argument gives the byte offset at which to start parsing the fields. This
+        helps defining extended parser deriving from a base parser:
+        \code
+           struct ExtendedParser : public BaseParser
+           {
+               ExtendedParser(data_iterator i, state_type s) : BaseParser(i,s) {}
+        
+               SENF_PACKET_PARSER_DEFINE_FIELDS_OFFSET(senf::bytes(BaseParser(*this)),
+                 ( ... fields ... ) );
+
+               void init() {
+                   BaseParser::init();
+                   defaultInit();
+                   // other init code
+               }
+           }
+        \endcode
+
+        \ingroup packetparsermacros
+        \hideinitializer
+     */
+#   define SENF_PACKET_PARSER_DEFINE_FIELDS_OFFSET(offset,fields)                                 \
+    SENF_PACKET_PARSER_I_DEFINE_FIELDS(offset,fields)
+
     /** \brief Define fields for a fixed size parser
 
         Define the fields as specified in \a fields. This macro only supports fixed size
@@ -363,15 +587,61 @@ namespace senf {
         \hideinitializer
      */
 #   define SENF_PACKET_PARSER_DEFINE_FIXED_FIELDS(fields)                                         \
-    SENF_PACKET_PARSER_I_DEFINE_FIXED_FIELDS(fields)
+    SENF_PACKET_PARSER_I_DEFINE_FIXED_FIELDS(0,fields)
+
+    /** \brief Define fields for a fixed size parser
+
+        Define the fields as specified in \a fields. This macro only supports fixed size
+        subfields, the resulting parser will also be a fixed size parser.
 
+        The \a offset argument gives the byte offset at which to start parsing the fields. This
+        helps defining extended parser deriving from a base parser:
+        \code
+           struct ExtendedParser : public BaseParser
+           {
+               ExtendedParser(data_iterator i, state_type s) : BaseParser(i,s) {}
+
+               SENF_PACKET_PARSER_DEFINE_FIXED_FIELDS_OFFSET(BaseParser::fixed_bytes,
+                 ( ... fields ... ) );
+
+               void init() {
+                   BaseParser::init();
+                   defaultInit();
+                   // other init code
+               }
+           }
+        \endcode
+
+        \ingroup packetparsermacros
+        \hideinitializer
+     */
+#   define SENF_PACKET_PARSER_DEFINE_FIXED_FIELDS_OFFSET(offset,fields)                           \
+    SENF_PACKET_PARSER_I_DEFINE_FIXED_FIELDS(offset,fields)
+
+    /** \brief Default parser parsing nothing
+     */
     struct VoidPacketParser 
         : public PacketParserBase
     {
         SENF_PACKET_PARSER_INIT(VoidPacketParser);
     };
 
-    /** \brief
+    /** \brief Iterator re-validating Parser wrapper
+
+        An ordinary parser will be invalidated whenever the raw data container's size is
+        changed. This can complicate some algorithms considerably.
+
+        This wrapper will update the parsers iterator (the value returned by the i() member) on
+        every access. This ensures that the iterator will stay valid.
+
+        \attention Beware however, if you insert or remove data before the safe wrapper, the
+            location will \e not be updated accordingly and therefore the parser will be
+            invalid.
+
+        Additionally a SafePacketParser has an uninitialized state. The only allowed operations in
+        this state are the boolean test for validity and assigning another parser.
+
+        \ingroup packetparser
       */
     template <class Parser>
     class SafePacketParser
@@ -385,23 +655,26 @@ namespace senf {
         ///\name Structors and default members
         ///@{
 
-        // default default constructor
         // default copy constructor
         // default copy assignment
         // default destructor
-        SafePacketParser();
+        SafePacketParser();             ///< Create an empty uninitialized SafePacketParser
 
         // conversion constructors
-        SafePacketParser(Parser parser);
+        SafePacketParser(Parser parser); ///< Initialize SafePacketParser from \a parser
 
-        SafePacketParser & operator=(Parser parser);
+        SafePacketParser & operator=(Parser parser); ///< Assign \a parser to \c this
 
         ///@}
         ///////////////////////////////////////////////////////////////////////////
 
-        Parser operator*() const;
-        Parser const * operator->() const;
-        bool boolean_test() const;
+        Parser operator*() const;       ///< Access the stored parser
+                                        /**< On every access, the stored parsers iterator will be
+                                             updated / re-validated. */
+        Parser const * operator->() const; ///< Access the stored parser
+                                        /**< On every access, the stored parsers iterator will be
+                                             updated / re-validated. */
+        bool boolean_test() const;      ///< Check validity
 
     protected:
 
@@ -413,6 +686,9 @@ namespace senf {
 }
 
 ///////////////////////////////hh.e////////////////////////////////////////
+#endif
+#if !defined(SENF_PACKETS_DECL_ONLY) && !defined(HH_PacketParser_i_)
+#define HH_PacketParser_i_
 #include "PacketParser.cci"
 #include "PacketParser.ct"
 #include "PacketParser.cti"
@@ -425,4 +701,7 @@ namespace senf {
 // c-file-style: "senf"
 // indent-tabs-mode: nil
 // ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// comment-column: 40
 // End:
+