> +(define-record-type* <configuration-field> > + configuration-field make-configuration-field configuration-field? > + (name configuration-field-name) > + (type configuration-field-type) > + (getter configuration-field-getter) > + (predicate configuration-field-predicate) > + (serializer configuration-field-serializer) > + (default-value-thunk configuration-field-default-value-thunk) > + (documentation configuration-field-documentation)) > + > +(define-syntax define-configuration > + (lambda (stx) > + (define (id ctx part . parts) > + (let ((part (syntax->datum part))) > + (datum->syntax > + ctx > + (match parts > + (() part) > + (parts (symbol-append part > + (syntax->datum (apply id ctx parts)))))))) > + (syntax-case stx () > + ((_ stem (field (field-type def) doc) ...) > + (with-syntax (((field-getter ...) > + (map (lambda (field) > + (id #'stem #'stem #'- field)) > + #'(field ...))) > + ((field-predicate ...) > + (map (lambda (type) > + (id #'stem type #'?)) > + #'(field-type ...))) > + ((field-serializer ...) > + (map (lambda (type) > + (id #'stem #'serialize- type)) > + #'(field-type ...)))) > + #`(begin > + (define-record-type* #,(id #'stem #'< #'stem #'>) > + stem #,(id #'stem #'make- #'stem) #,(id #'stem #'stem #'?) > + (field field-getter (default def)) > + ...) > + (define #,(id #'stem #'stem #'-fields) > + (list (configuration-field > + (name 'field) > + (type 'field-type) > + (getter field-getter) > + (predicate field-predicate) > + (serializer field-serializer) > + (default-value-thunk (lambda () def)) > + (documentation doc)) > + ...)))))))) > + > +(define (serialize-configuration config fields) > + (for-each (lambda (field) > + ((configuration-field-serializer field) > + (configuration-field-name field) > + ((configuration-field-getter field) config))) > + fields)) > + > +(define (validate-configuration config fields) > + (for-each (lambda (field) > + (let ((val ((configuration-field-getter field) config))) > + (unless ((configuration-field-predicate field) val) > + (cups-configuration-field-error > + (configuration-field-name field) val)))) > + fields))
These definitions are also in the Dovecot service. Would it make sense to put them in a place where they could be accessible from other services as well, thus avoiding code repetition?