diff --git a/src/clj/coffi/mem.clj b/src/clj/coffi/mem.clj index e53d489..33b91f6 100644 --- a/src/clj/coffi/mem.clj +++ b/src/clj/coffi/mem.clj @@ -1546,6 +1546,33 @@ :args (s/cat :new-type qualified-keyword? :aliased-type any?)) +(defn- with-c-layout + "Forces a struct specification to C layout rules. + + This will add padding fields between fields to match C alignment + requirements." + [struct-spec] + (let [aligned-fields + (loop [offset 0 + aligned-fields [] + fields (nth struct-spec 1)] + (if (seq fields) + (let [[[_ type :as field] & fields] fields + size (mem/size-of type) + align (mem/align-of type) + r (rem offset align)] + (recur (cond-> (+ offset size) + (pos? r) (+ (- align r))) + (cond-> aligned-fields + (pos? r) (conj [::padding [::mem/padding (- align r)]]) + :always (conj field)) + fields)) + (let [strongest-alignment (reduce max (map (comp mem/align-of second) (nth struct-spec 1))) + r (rem offset strongest-alignment)] + (cond-> aligned-fields + (pos? r) (conj [::padding [::mem/padding (- strongest-alignment r)]])))))] + (assoc struct-spec 1 aligned-fields))) + (defn- typename->coffi-typename [_type] (get {'byte ::byte