As a security rule, you cannot create a cast without owning one of the types. This was a problem for me because I wanted a cast from bool to bigint, and there isn't one.
The following code successfully creates it, not as postgres and not as a superuser. I'm glad it works, but the ease of this eliminates most of why I think you might want a security rule like the above:
CREATE OR REPLACE FUNCTION public.to_bigint (p_bool BOOL)
RETURNS BIGINT
language 'sql' AS $$
SELECT p_bool::int::bigint;
$$;
do $$
DECLARE
v_owner TEXT;
BEGIN
SELECT rolname::text
FROM pg_type t
JOIN pg_roles r
ON t.typowner = r.oid
WHERE t.typname = 'bool'
INTO v_owner;
ALTER TYPE bool OWNER TO current_user;
DROP CAST IF EXISTS (bool AS bigint);
CREATE CAST (bool AS bigint)
WITH FUNCTION public.to_bigint;
EXECUTE 'ALTER TYPE bool OWNER TO ' || v_owner;
END
$$;