Fixed .la dependency tracking for -lpthread
[barry.git] / src / builder.h
blobac9e512982a5931b612f32559413ed910b64599b
1 ///
2 /// \file builder.h
3 /// Virtual protocol packet builder wrapper
4 ///
6 /*
7 Copyright (C) 2005-2011, Net Direct Inc. (http://www.netdirect.ca/)
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18 See the GNU General Public License in the COPYING file at the
19 root directory of this project for more details.
22 #ifndef __BARRY_BUILDER_H__
23 #define __BARRY_BUILDER_H__
25 #include "dll.h"
26 #include "data.h"
27 #include <stdint.h>
28 #include <string>
31 // This macro can be used to automatically generate code for all known
32 // record types. Just #undef HANDLE_BUILDER, then #define it to whatever
33 // you need, then use ALL_KNOWN_BUILDER_TYPES. See parser.cc for
34 // various examples.
36 // These are sorted so their GetDBName()'s will display in alphabetical order.
38 #define ALL_KNOWN_BUILDER_TYPES \
39 HANDLE_BUILDER(Contact) \
40 HANDLE_BUILDER(Calendar) \
41 HANDLE_BUILDER(CalendarAll) \
42 HANDLE_BUILDER(ContentStore) \
43 HANDLE_BUILDER(Memo) \
44 HANDLE_BUILDER(Task) \
46 namespace Barry {
48 // forward declarations
49 class IConverter;
52 // Builder class
54 /// Base class for the builder functor hierarchy.
55 ///
56 /// This defines the API used by the Controller and Packet classes
57 /// for building a raw device record to write to the device.
58 ///
59 class BXEXPORT Builder
61 public:
62 Builder() {}
63 virtual ~Builder() {}
65 /// Called to build the record field data. Store the raw data
66 /// in data, using offset to know where to write. Be sure to
67 /// update offset, and be sure to adjust the size of the data
68 /// packet (possibly with Data::ReleaseBuffer()).
69 ///
70 /// Returns true if successful, and false if at the end of
71 /// the series. Note that if EndOfFile() is false after
72 /// this function returns false, then there may be another
73 /// series available, which the next call to BuildRecord()
74 /// will determine.
75 ///
76 virtual bool BuildRecord(DBData &data, size_t &offset,
77 const IConverter *ic) = 0;
79 /// Same as BuildRecord, but does not care about any offsets.
80 /// The caller should call DBData::GetOffset() afterward
81 /// to discover if there is an offset to the result.
82 ///
83 /// This is usually the fastest of the two functions, since
84 /// extra copying may be required if a specific offset is
85 /// given. When building records from Record classes, both
86 /// functions are the same speed. But when building records
87 /// from the device, the device decides the offset, so FetchRecord()
88 /// is faster, since BuildRecord requires a copy to adjust
89 /// to the right offset.
90 ///
91 /// The caller should use the function that results in the least
92 /// amount of copying for the caller. If the caller doesn't
93 /// care about where the resulting record is in data, use
94 /// FetchRecord().
95 ///
96 virtual bool FetchRecord(DBData &data, const IConverter *ic) = 0;
98 /// Sometimes a builder can have multiple databases stored
99 /// in it, so when Build/Fetch returns false, check if there
100 /// is more data with this function. This function is
101 /// not used by database-oriented functions, but by pipe-
102 /// oriented functions.
103 virtual bool EndOfFile() const = 0;
108 // DBDataBuilder
110 /// Wrapper class around a DBData object, to make it easy to pass a DBData
111 /// object into a function or API that requires a builder. The main
112 /// advantage to this is that the Builder API allows for movement of
113 /// data, depending on the required offsets.
115 class BXEXPORT DBDataBuilder : public Builder
117 const DBData &m_orig;
119 public:
120 explicit DBDataBuilder(const DBData &orig);
121 virtual ~DBDataBuilder();
123 virtual bool BuildRecord(DBData &data, size_t &offset,
124 const IConverter *ic);
125 virtual bool FetchRecord(DBData &data, const IConverter *ic);
126 virtual bool EndOfFile() const;
130 // SetDBData
132 /// Contains the proper way to convert a record object into a DBData object.
134 template <class RecordT>
135 void SetDBData(const RecordT &rec, DBData &data, size_t &offset,
136 const IConverter *ic)
138 data.SetVersion(DBData::REC_VERSION_1);
139 data.SetOffset(offset);
140 data.SetDBName(RecordT::GetDBName());
141 data.SetIds(rec.GetRecType(), rec.GetUniqueId());
142 rec.BuildHeader(data.UseData(), offset);
143 rec.BuildFields(data.UseData(), offset, ic);
147 // RecordBuilder template class
149 /// Template class for easy creation of specific protocol packet builder
150 /// objects. This template takes the following template arguments:
152 /// - RecordT: One of the record classes in record.h
153 /// - StorageT: A custom storage functor class. An object of this type
154 /// will be called as a function with empty Record as an
155 /// argument. The storage class is expected to fill the
156 /// record object in preparation for building the packet
157 /// out of that data. These calls happen on the fly as the data
158 /// is sent to the device over USB, so it should not block forever.
160 /// Example SaveDatabase() call:
162 /// <pre>
163 /// FIXME
164 /// </pre>
166 template <class RecordT, class StorageT>
167 class RecordBuilder : public Builder
169 StorageT *m_storage;
170 bool m_owned;
171 bool m_record_loaded;
172 bool m_end_of_file;
173 RecordT m_rec;
175 public:
176 /// Constructor that references an externally managed storage object.
177 RecordBuilder(StorageT &storage)
178 : m_storage(&storage)
179 , m_owned(false)
180 , m_record_loaded(false)
181 , m_end_of_file(false)
185 /// Constructor that references a locally managed storage object.
186 /// The pointer passed in will be stored, and freed when this class
187 /// is destroyed. It is safe to call this constructor with
188 /// a 'new'ly created storage object.
189 RecordBuilder(StorageT *storage)
190 : m_storage(storage)
191 , m_owned(true)
192 , m_record_loaded(false)
193 , m_end_of_file(false)
197 ~RecordBuilder()
199 if( this->m_owned )
200 delete m_storage;
203 virtual bool BuildRecord(DBData &data, size_t &offset,
204 const IConverter *ic)
206 if( m_end_of_file )
207 return false;
209 if( !(*m_storage)(m_rec, *this) ) {
210 m_end_of_file = true;
211 return false;
214 SetDBData(m_rec, data, offset, ic);
215 return true;
218 virtual bool FetchRecord(DBData &data, const IConverter *ic)
220 size_t offset = 0;
221 return BuildRecord(data, offset, ic);
224 virtual bool EndOfFile() const
226 return m_end_of_file;
232 // RecordFetch template class
234 /// Generic record fetch class, to help with using records without
235 /// builder classes.
237 template <class RecordT>
238 class RecordFetch
240 const RecordT &m_rec;
241 mutable bool m_done;
243 public:
244 RecordFetch(const RecordT &rec) : m_rec(rec), m_done(false) {}
245 bool operator()(RecordT &rec, Builder &) const
247 if( m_done )
248 return false;
249 rec = m_rec;
250 m_done = true;
251 return true;
256 } // namespace Barry
258 #endif