{"id":13803687,"url":"https://github.com/bohonghuang/cffi-ops","last_synced_at":"2025-05-13T16:32:27.888Z","repository":{"id":173560796,"uuid":"650709543","full_name":"bohonghuang/cffi-ops","owner":"bohonghuang","description":"A Common Lisp library that helps write concise CFFI-related code.","archived":false,"fork":false,"pushed_at":"2025-02-17T16:19:24.000Z","size":48,"stargazers_count":45,"open_issues_count":0,"forks_count":1,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-02-17T17:29:58.595Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Common Lisp","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bohonghuang.png","metadata":{"files":{"readme":"README.org","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-06-07T16:31:00.000Z","updated_at":"2025-02-17T16:19:28.000Z","dependencies_parsed_at":null,"dependency_job_id":"365a33be-7b99-4d11-83f4-a5c8ab1cf779","html_url":"https://github.com/bohonghuang/cffi-ops","commit_stats":null,"previous_names":["bohonghuang/cffi-ops"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bohonghuang%2Fcffi-ops","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bohonghuang%2Fcffi-ops/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bohonghuang%2Fcffi-ops/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bohonghuang%2Fcffi-ops/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bohonghuang","download_url":"https://codeload.github.com/bohonghuang/cffi-ops/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253981929,"owners_count":21994359,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-04T01:00:36.915Z","updated_at":"2025-05-13T16:32:22.879Z","avatar_url":"https://github.com/bohonghuang.png","language":"Common Lisp","funding_links":[],"categories":["C ##"],"sub_categories":[],"readme":"#+TITLE: cffi-ops\nWrite CFFI stuff quickly without runtime overhead.\n* Introduction\nCFFI is powerful, but using its API to write C-style code can sometimes be cumbersome because it requires you to repeatedly pass in types,\nunlike the dot operator in C that has some type inference capabilities.\n\nThis library provides CFFI with dot operator-like functionality at compile time,\nallowing you to write CFFI-related code as simple as C with just a small amount of FFI type declarations.\n\nThis library has been tested to work on SBCL, CCL, ECL, ABCL, and CLISP,\nand theoretically is portable across implementations that provide ~macroexpand-all~.\n* Rules\nHere is a comparison table between C syntax:\n\n| C                        | ~cffi-ops~                                                                       |\n|--------------------------+--------------------------------------------------------------------------------|\n| ~x-\u003ey.z~ or ~x-\u003ey-\u003ez~        | ~(-\u003e x y z)~ (Note that ~x~, ~y~, and ~z~ must be the same symbols used in ~defcstruct~) |\n| ~\u0026x-\u003ey~                    | ~(\u0026 (-\u003e x y))~                                                                   |\n| ~*x~                       | ~([] x)~                                                                         |\n| ~x[n]~                     | ~([] x n)~                                                                       |\n| ~\u0026x[n]~ or ~x + n~           | ~(\u0026 ([] x n))~                                                                   |\n| ~x.y = z~                  | ~(setf (-\u003e x y) z)~ if ~z~ is a variable                                           |\n|                          | ~(csetf (-\u003e x y) z)~ if ~z~ is a CFFI pointer                                      |\n| ~A _a, *a = \u0026_a~           | ~(clet ((a (foreign-alloca '(:struct A)))) ...)~                                 |\n| ~A *a = malloc(sizeof(A))~ | ~(clet ((a (cffi:foreign-alloc '(:struct A)))) ...)~                             |\n| ~A _a = *b, *a = \u0026_a~      | ~(clet ((a ([] b))) ...)~                                                        |\n| ~A *a = b~                 | ~(clet ((a b)) ...)~                                                             |\n\nPlease note that since it is not possible to directly manipulate C compound types in Lisp,\nbinding and assignment of compound types require the use of ~clet~ (or ~clet*~) and ~csetf~,\nwhich bind and operate on variables that are CFFI pointers.\n\nAnd the symbol ~-\u003e~ is directly exported from the [[https://github.com/hipeta/arrow-macros][arrow-macros]] package,\nso this library is fully compatible with ~arrow-macros~,\nwhich means you can freely use all the macros (including ~-\u003e~) provided by ~arrow-macros~ inside or outside of ~clocally~, ~clet~, ~clet*~, or ~csetf~.\n* Example\nFor the following C code:\n\n#+BEGIN_SRC c\n  #include \u003cstdlib.h\u003e\n  #include \u003cassert.h\u003e\n\n  typedef struct {\n    float x;\n    float y;\n    float z;\n  } Vector3;\n\n  typedef struct {\n    Vector3 v1;\n    Vector3 v2;\n    Vector3 v3;  \n  } Matrix3;\n\n  void Vector3Add(Vector3 *output, const Vector3 *v1, const Vector3 *v2) {\n    output-\u003ex = v1-\u003ex + v2-\u003ex;\n    output-\u003ey = v1-\u003ey + v2-\u003ey;\n    output-\u003ez = v1-\u003ez + v2-\u003ez;\n  }\n\n  int main(int argc, char *argv[]) {\n    Matrix3 m1[3];\n    m1[0].v1.x = 1.0;\n    m1[0].v1.y = 2.0;\n    m1[0].v1.z = 3.0;\n    Matrix3 m2 = *m1;\n    Vector3 *v1 = \u0026m2.v1;\n    Vector3 *v2 = malloc(sizeof(Vector3));\n    ,*v2 = *v1;\n    v2-\u003ex = 3.0;\n    v2-\u003ez = 1.0;\n    Vector3Add(v1, v1, v2);\n    assert(v1-\u003ex == 4.0);\n    assert(v1-\u003ey == 4.0);\n    assert(v1-\u003ez == 4.0);\n    free(v2);\n    return 0;\n  }\n#+END_SRC\n\nThe equivalent Lisp code (written using ~cffi-ops~) is:\n\n#+BEGIN_SRC lisp\n  (defpackage cffi-ops-example\n    (:use #:cl #:cffi #:cffi-ops))\n\n  (in-package #:cffi-ops-example)\n\n  (defcstruct vector3\n    (x :float)\n    (y :float)\n    (z :float))\n\n  (defcstruct matrix3\n    (v1 (:struct vector3))\n    (v2 (:struct vector3))\n    (v3 (:struct vector3)))\n\n  (defun vector3-add (output v1 v2)\n    (clocally\n      (declare (ctype (:pointer (:struct vector3)) output v1 v2))\n      (setf (-\u003e output x) (+ (-\u003e v1 x) (-\u003e v2 x))\n            (-\u003e output y) (+ (-\u003e v1 y) (-\u003e v2 y))\n            (-\u003e output z) (+ (-\u003e v1 z) (-\u003e v2 z)))))\n\n  (defun main ()\n    (clet ((m1 (foreign-alloca '(:array (:struct matrix3) 3))))\n      (setf (-\u003e ([] m1 0) v1 x) 1.0\n            (-\u003e ([] m1 0) v1 y) 2.0\n            (-\u003e ([] m1 0) v1 z) 3.0)\n      (clet* ((m2 ([] m1))\n              (v1 (\u0026 (-\u003e m2 v1)))\n              (v2 (foreign-alloc '(:struct vector3))))\n        (csetf ([] v2) ([] v1))\n        (setf (-\u003e v2 x) 3.0\n              (-\u003e v2 z) 1.0)\n        (vector3-add v1 v1 v2)\n        (assert (= (-\u003e v1 x) 4.0))\n        (assert (= (-\u003e v1 y) 4.0))\n        (assert (= (-\u003e v1 z) 4.0))\n        (foreign-free v2))))\n#+END_SRC\n\nAnd the equivalent Lisp code (written without using ~cffi-ops~) is:\n\n#+BEGIN_SRC lisp\n  (defpackage cffi-example\n    (:use #:cl #:cffi))\n\n  (in-package #:cffi-example)\n\n  (defcstruct vector3\n    (x :float)\n    (y :float)\n    (z :float))\n\n  (defcstruct matrix3\n    (v1 (:struct vector3))\n    (v2 (:struct vector3))\n    (v3 (:struct vector3)))\n\n  (declaim (inline memcpy))\n  (defcfun \"memcpy\" :void\n    (dest :pointer)\n    (src :pointer)\n    (n :size))\n\n  (defun vector3-add (output v1 v2)\n    (with-foreign-slots (((xout x) (yout y) (zout z)) output (:struct vector3))\n      (with-foreign-slots (((x1 x) (y1 y) (z1 z)) v1 (:struct vector3))\n        (with-foreign-slots (((x2 x) (y2 y) (z2 z)) v2 (:struct vector3))\n          (setf xout (+ x1 x2) yout (+ y1 y2) zout (+ z1 z2))))))\n\n  (defun main ()\n    (with-foreign-object (m1 '(:struct matrix3) 3)\n      (with-foreign-slots ((x y z)\n                           (foreign-slot-pointer\n                            (mem-aptr m1 '(:struct matrix3) 0)\n                            '(:struct matrix3) 'v1)\n                           (:struct vector3))\n        (setf x 1.0 y 2.0 z 3.0))\n      (with-foreign-object (m2 '(:struct matrix3))\n        (memcpy m2 m1 (foreign-type-size '(:struct matrix3)))\n        (let ((v1 (foreign-slot-pointer m2 '(:struct matrix3) 'v1))\n              (v2 (foreign-alloc '(:struct vector3))))\n          (memcpy v2 v1 (foreign-type-size '(:struct vector3)))\n          (with-foreign-slots ((x z) v2 (:struct vector3))\n            (setf x 3.0 z 1.0))\n          (vector3-add v1 v1 v2)\n          (with-foreign-slots ((x y z) v1 (:struct vector3))\n            (assert (= x 4.0))\n            (assert (= y 4.0))\n            (assert (= z 4.0)))\n          (foreign-free v2)))))\n#+END_SRC\n\nBoth of them should generate almost equivalent machine code in SBCL and have very similar performance.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbohonghuang%2Fcffi-ops","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbohonghuang%2Fcffi-ops","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbohonghuang%2Fcffi-ops/lists"}